| Index: chrome/browser/password_manager/password_store_kwallet.cc
|
| ===================================================================
|
| --- chrome/browser/password_manager/password_store_kwallet.cc (revision 48891)
|
| +++ chrome/browser/password_manager/password_store_kwallet.cc (working copy)
|
| @@ -1,4 +1,4 @@
|
| -// Copyright (c) 2006-2009 The Chromium Authors. All rights reserved.
|
| +// Copyright (c) 2010 The Chromium Authors. All rights reserved.
|
| // Use of this source code is governed by a BSD-style license that can be
|
| // found in the LICENSE file.
|
|
|
| @@ -9,12 +9,16 @@
|
| #include "base/logging.h"
|
| #include "base/md5.h"
|
| #include "base/pickle.h"
|
| +#include "base/stl_util-inl.h"
|
| #include "base/string_util.h"
|
| #include "base/task.h"
|
|
|
| using std::string;
|
| using std::vector;
|
| +using webkit_glue::PasswordForm;
|
|
|
| +// We could localize these strings, but then changing your locale would cause
|
| +// you to lose access to all your stored passwords. Maybe best not to do that.
|
| const char* PasswordStoreKWallet::kAppId = "Chrome";
|
| const char* PasswordStoreKWallet::kKWalletFolder = "Chrome Form Data";
|
|
|
| @@ -25,7 +29,9 @@
|
| const char* PasswordStoreKWallet::kKLauncherPath = "/KLauncher";
|
| const char* PasswordStoreKWallet::kKLauncherInterface = "org.kde.KLauncher";
|
|
|
| -PasswordStoreKWallet::PasswordStoreKWallet()
|
| +PasswordStoreKWallet::PasswordStoreKWallet(LoginDatabase* login_db,
|
| + Profile* profile,
|
| + WebDataService* web_data_service)
|
| : error_(NULL),
|
| connection_(NULL),
|
| proxy_(NULL) {
|
| @@ -38,13 +44,6 @@
|
| }
|
|
|
| bool PasswordStoreKWallet::Init() {
|
| - thread_.reset(new base::Thread("Chrome_KeyringThread"));
|
| -
|
| - if (!thread_->Start()) {
|
| - thread_.reset(NULL);
|
| - return false;
|
| - }
|
| -
|
| // Initialize threading in dbus-glib - it should be fine for
|
| // dbus_g_thread_init to be called multiple times.
|
| if (!g_thread_supported())
|
| @@ -56,8 +55,11 @@
|
| if (CheckError())
|
| return false;
|
|
|
| - if (!StartKWalletd()) return false;
|
| - if (!InitWallet()) return false;
|
| + if (!InitWallet()) {
|
| + // kwalletd may not be running. Try to start it and try again.
|
| + if (!StartKWalletd() || !InitWallet())
|
| + return false;
|
| + }
|
|
|
| return true;
|
| }
|
| @@ -134,11 +136,12 @@
|
| return;
|
|
|
| PasswordFormList forms;
|
| - GetLoginsList(&forms, form, wallet_handle);
|
| + GetLoginsList(&forms, form.signon_realm, wallet_handle);
|
|
|
| - forms.push_back(const_cast<PasswordForm*>(&form));
|
| + forms.push_back(new PasswordForm(form));
|
| + SetLoginsList(forms, form.signon_realm, wallet_handle);
|
|
|
| - SetLoginsList(forms, form, wallet_handle);
|
| + STLDeleteElements(&forms);
|
| }
|
|
|
| void PasswordStoreKWallet::UpdateLoginImpl(const PasswordForm& form) {
|
| @@ -148,16 +151,16 @@
|
| return;
|
|
|
| PasswordFormList forms;
|
| - GetLoginsList(&forms, form, wallet_handle);
|
| + GetLoginsList(&forms, form.signon_realm, wallet_handle);
|
|
|
| - for (uint i = 0; i < forms.size(); ++i) {
|
| - if (CompareForms(form, *forms[i])) {
|
| - forms.erase(forms.begin() + i);
|
| - forms.insert(forms.begin() + i, const_cast<PasswordForm*>(&form));
|
| - }
|
| + for (size_t i = 0; i < forms.size(); ++i) {
|
| + if (CompareForms(form, *forms[i], true))
|
| + *forms[i] = form;
|
| }
|
|
|
| - SetLoginsList(forms, form, wallet_handle);
|
| + SetLoginsList(forms, form.signon_realm, wallet_handle);
|
| +
|
| + STLDeleteElements(&forms);
|
| }
|
|
|
| void PasswordStoreKWallet::RemoveLoginImpl(const PasswordForm& form) {
|
| @@ -166,57 +169,126 @@
|
| if (wallet_handle == kInvalidKWalletHandle)
|
| return;
|
|
|
| - PasswordFormList forms;
|
| - GetLoginsList(&forms, form, wallet_handle);
|
| + PasswordFormList all_forms;
|
| + GetLoginsList(&all_forms, form.signon_realm, wallet_handle);
|
|
|
| - for (uint i = 0; i < forms.size(); ++i) {
|
| - if (CompareForms(form, *forms[i])) {
|
| - forms.erase(forms.begin() + i);
|
| - --i;
|
| - }
|
| + PasswordFormList kept_forms;
|
| + kept_forms.reserve(all_forms.size());
|
| + for (size_t i = 0; i < all_forms.size(); ++i) {
|
| + if (CompareForms(form, *all_forms[i], false))
|
| + delete all_forms[i];
|
| + else
|
| + kept_forms.push_back(all_forms[i]);
|
| }
|
|
|
| - if (forms.empty()) {
|
| - // No items left? Remove the entry from the wallet.
|
| - int ret = 0;
|
| - dbus_g_proxy_call(proxy_, "removeEntry", &error_,
|
| - G_TYPE_INT, wallet_handle, // handle
|
| - G_TYPE_STRING, kKWalletFolder, // folder
|
| - G_TYPE_STRING, form.signon_realm.c_str(), // key
|
| - G_TYPE_STRING, kAppId, // appid
|
| + // Update the entry in the wallet.
|
| + SetLoginsList(kept_forms, form.signon_realm, wallet_handle);
|
| + STLDeleteElements(&kept_forms);
|
| +}
|
| +
|
| +void PasswordStoreKWallet::RemoveLoginsCreatedBetweenImpl(
|
| + const base::Time& delete_begin,
|
| + const base::Time& delete_end) {
|
| + AutoLock l(kwallet_lock_);
|
| + int wallet_handle = WalletHandle();
|
| + if (wallet_handle == kInvalidKWalletHandle)
|
| + return;
|
| +
|
| + // We could probably also use readEntryList here.
|
| + char** realm_list = NULL;
|
| + dbus_g_proxy_call(proxy_, "entryList", &error_,
|
| + G_TYPE_INT, wallet_handle, // handle
|
| + G_TYPE_STRING, kKWalletFolder, // folder
|
| + G_TYPE_STRING, kAppId, // appid
|
| + G_TYPE_INVALID,
|
| + G_TYPE_STRV, &realm_list,
|
| + G_TYPE_INVALID);
|
| + if (CheckError())
|
| + return;
|
| +
|
| + for (char** realm = realm_list; *realm; ++realm) {
|
| + GArray* byte_array = NULL;
|
| + dbus_g_proxy_call(proxy_, "readEntry", &error_,
|
| + G_TYPE_INT, wallet_handle, // handle
|
| + G_TYPE_STRING, kKWalletFolder, // folder
|
| + G_TYPE_STRING, *realm, // key
|
| + G_TYPE_STRING, kAppId, // appid
|
| G_TYPE_INVALID,
|
| - G_TYPE_INT, &ret,
|
| + DBUS_TYPE_G_UCHAR_ARRAY, &byte_array,
|
| G_TYPE_INVALID);
|
| - CheckError();
|
| - if (ret)
|
| - LOG(ERROR) << "Bad return code " << ret << " from kwallet removeEntry";
|
| - } else {
|
| - // Otherwise update the entry in the wallet.
|
| - SetLoginsList(forms, form, wallet_handle);
|
| +
|
| + if (CheckError() || !byte_array || !byte_array->len)
|
| + continue;
|
| +
|
| + string signon_realm(*realm);
|
| + Pickle pickle(byte_array->data, byte_array->len);
|
| + PasswordFormList all_forms;
|
| + DeserializeValue(signon_realm, pickle, &all_forms);
|
| + g_array_free(byte_array, true);
|
| +
|
| + PasswordFormList kept_forms;
|
| + kept_forms.reserve(all_forms.size());
|
| + for (size_t i = 0; i < all_forms.size(); ++i) {
|
| + if (delete_begin <= all_forms[i]->date_created &&
|
| + (delete_end.is_null() || all_forms[i]->date_created < delete_end)) {
|
| + delete all_forms[i];
|
| + } else {
|
| + kept_forms.push_back(all_forms[i]);
|
| + }
|
| + }
|
| +
|
| + SetLoginsList(kept_forms, signon_realm, wallet_handle);
|
| + STLDeleteElements(&kept_forms);
|
| }
|
| + g_strfreev(realm_list);
|
| }
|
|
|
| -void PasswordStoreKWallet::GetLoginsImpl(GetLoginsRequest* request) {
|
| +void PasswordStoreKWallet::GetLoginsImpl(GetLoginsRequest* request,
|
| + const PasswordForm& form) {
|
| PasswordFormList forms;
|
|
|
| AutoLock l(kwallet_lock_);
|
| int wallet_handle = WalletHandle();
|
| if (wallet_handle != kInvalidKWalletHandle)
|
| - GetLoginsList(&forms, request->form, wallet_handle);
|
| + GetLoginsList(&forms, form.signon_realm, wallet_handle);
|
|
|
| NotifyConsumer(request, forms);
|
| }
|
|
|
| +void PasswordStoreKWallet::GetAutofillableLoginsImpl(
|
| + GetLoginsRequest* request) {
|
| + std::vector<PasswordForm*> forms;
|
| + FillAutofillableLogins(&forms);
|
| + NotifyConsumer(request, forms);
|
| +}
|
| +
|
| +void PasswordStoreKWallet::GetBlacklistLoginsImpl(
|
| + GetLoginsRequest* request) {
|
| + std::vector<PasswordForm*> forms;
|
| + FillBlacklistLogins(&forms);
|
| + NotifyConsumer(request, forms);
|
| +}
|
| +
|
| +bool PasswordStoreKWallet::FillAutofillableLogins(
|
| + std::vector<PasswordForm*>* forms) {
|
| + return FillSomeLogins(true, forms);
|
| +}
|
| +
|
| +bool PasswordStoreKWallet::FillBlacklistLogins(
|
| + std::vector<PasswordForm*>* forms) {
|
| + return FillSomeLogins(false, forms);
|
| +}
|
| +
|
| void PasswordStoreKWallet::GetLoginsList(PasswordFormList* forms,
|
| - const PasswordForm& key,
|
| + const string& signon_realm,
|
| int wallet_handle) {
|
| // Is there an entry in the wallet?
|
| gboolean has_entry = false;
|
| dbus_g_proxy_call(proxy_, "hasEntry", &error_,
|
| - G_TYPE_INT, wallet_handle, // handle
|
| - G_TYPE_STRING, kKWalletFolder, // folder
|
| - G_TYPE_STRING, key.signon_realm.c_str(), // key
|
| - G_TYPE_STRING, kAppId, // appid
|
| + G_TYPE_INT, wallet_handle, // handle
|
| + G_TYPE_STRING, kKWalletFolder, // folder
|
| + G_TYPE_STRING, signon_realm.c_str(), // key
|
| + G_TYPE_STRING, kAppId, // appid
|
| G_TYPE_INVALID,
|
| G_TYPE_BOOLEAN, &has_entry,
|
| G_TYPE_INVALID);
|
| @@ -226,10 +298,10 @@
|
|
|
| GArray* byte_array = NULL;
|
| dbus_g_proxy_call(proxy_, "readEntry", &error_,
|
| - G_TYPE_INT, wallet_handle, // handle
|
| - G_TYPE_STRING, kKWalletFolder, // folder
|
| - G_TYPE_STRING, key.signon_realm.c_str(), // key
|
| - G_TYPE_STRING, kAppId, // appid
|
| + G_TYPE_INT, wallet_handle, // handle
|
| + G_TYPE_STRING, kKWalletFolder, // folder
|
| + G_TYPE_STRING, signon_realm.c_str(), // key
|
| + G_TYPE_STRING, kAppId, // appid
|
| G_TYPE_INVALID,
|
| DBUS_TYPE_G_UCHAR_ARRAY, &byte_array,
|
| G_TYPE_INVALID);
|
| @@ -238,12 +310,30 @@
|
| return;
|
|
|
| Pickle pickle(byte_array->data, byte_array->len);
|
| - DeserializeValue(key, pickle, forms);
|
| + DeserializeValue(signon_realm, pickle, forms);
|
| + g_array_free(byte_array, true);
|
| }
|
|
|
| void PasswordStoreKWallet::SetLoginsList(const PasswordFormList& forms,
|
| - const PasswordForm& key,
|
| + const string& signon_realm,
|
| int wallet_handle) {
|
| + if (forms.empty()) {
|
| + // No items left? Remove the entry from the wallet.
|
| + int ret = 0;
|
| + dbus_g_proxy_call(proxy_, "removeEntry", &error_,
|
| + G_TYPE_INT, wallet_handle, // handle
|
| + G_TYPE_STRING, kKWalletFolder, // folder
|
| + G_TYPE_STRING, signon_realm.c_str(), // key
|
| + G_TYPE_STRING, kAppId, // appid
|
| + G_TYPE_INVALID,
|
| + G_TYPE_INT, &ret,
|
| + G_TYPE_INVALID);
|
| + CheckError();
|
| + if (ret != 0)
|
| + LOG(ERROR) << "Bad return code " << ret << " from kwallet removeEntry";
|
| + return;
|
| + }
|
| +
|
| Pickle value;
|
| SerializeValue(forms, &value);
|
|
|
| @@ -255,74 +345,144 @@
|
| // Make the call.
|
| int ret = 0;
|
| dbus_g_proxy_call(proxy_, "writeEntry", &error_,
|
| - G_TYPE_INT, wallet_handle, // handle
|
| - G_TYPE_STRING, kKWalletFolder, // folder
|
| - G_TYPE_STRING, key.signon_realm.c_str(), // key
|
| - DBUS_TYPE_G_UCHAR_ARRAY, byte_array, // value
|
| - G_TYPE_STRING, kAppId, // appid
|
| + G_TYPE_INT, wallet_handle, // handle
|
| + G_TYPE_STRING, kKWalletFolder, // folder
|
| + G_TYPE_STRING, signon_realm.c_str(), // key
|
| + DBUS_TYPE_G_UCHAR_ARRAY, byte_array, // value
|
| + G_TYPE_STRING, kAppId, // appid
|
| G_TYPE_INVALID,
|
| G_TYPE_INT, &ret,
|
| G_TYPE_INVALID);
|
| g_array_free(byte_array, true);
|
|
|
| CheckError();
|
| - if (ret)
|
| + if (ret != 0)
|
| LOG(ERROR) << "Bad return code " << ret << " from kwallet writeEntry";
|
| }
|
|
|
| +bool PasswordStoreKWallet::FillSomeLogins(bool autofillable,
|
| + PasswordFormList* forms) {
|
| + AutoLock l(kwallet_lock_);
|
| + int wallet_handle = WalletHandle();
|
| + if (wallet_handle == kInvalidKWalletHandle)
|
| + return false;
|
| +
|
| + // We could probably also use readEntryList here.
|
| + char** realm_list = NULL;
|
| + dbus_g_proxy_call(proxy_, "entryList", &error_,
|
| + G_TYPE_INT, wallet_handle, // handle
|
| + G_TYPE_STRING, kKWalletFolder, // folder
|
| + G_TYPE_STRING, kAppId, // appid
|
| + G_TYPE_INVALID,
|
| + G_TYPE_STRV, &realm_list,
|
| + G_TYPE_INVALID);
|
| + if (CheckError())
|
| + return false;
|
| +
|
| + PasswordFormList all_forms;
|
| + for (char** realm = realm_list; *realm; ++realm) {
|
| + GArray* byte_array = NULL;
|
| + dbus_g_proxy_call(proxy_, "readEntry", &error_,
|
| + G_TYPE_INT, wallet_handle, // handle
|
| + G_TYPE_STRING, kKWalletFolder, // folder
|
| + G_TYPE_STRING, *realm, // key
|
| + G_TYPE_STRING, kAppId, // appid
|
| + G_TYPE_INVALID,
|
| + DBUS_TYPE_G_UCHAR_ARRAY, &byte_array,
|
| + G_TYPE_INVALID);
|
| +
|
| + if (CheckError() || !byte_array || !byte_array->len)
|
| + continue;
|
| +
|
| + Pickle pickle(byte_array->data, byte_array->len);
|
| + DeserializeValue(*realm, pickle, &all_forms);
|
| + g_array_free(byte_array, true);
|
| + }
|
| + g_strfreev(realm_list);
|
| +
|
| + // We have to read all the entries, and then filter them here.
|
| + forms->reserve(forms->size() + all_forms.size());
|
| + for (size_t i = 0; i < all_forms.size(); ++i) {
|
| + if (all_forms[i]->blacklisted_by_user == !autofillable)
|
| + forms->push_back(all_forms[i]);
|
| + else
|
| + delete all_forms[i];
|
| + }
|
| +
|
| + return true;
|
| +}
|
| +
|
| bool PasswordStoreKWallet::CompareForms(const PasswordForm& a,
|
| - const PasswordForm& b) {
|
| + const PasswordForm& b,
|
| + bool update_check) {
|
| + // An update check doesn't care about the submit element.
|
| + if (!update_check && a.submit_element != b.submit_element)
|
| + return false;
|
| return a.origin == b.origin &&
|
| a.password_element == b.password_element &&
|
| a.signon_realm == b.signon_realm &&
|
| - a.submit_element == b.submit_element &&
|
| a.username_element == b.username_element &&
|
| a.username_value == b.username_value;
|
| }
|
|
|
| void PasswordStoreKWallet::SerializeValue(const PasswordFormList& forms,
|
| Pickle* pickle) {
|
| - pickle->WriteInt(forms.size());
|
| + pickle->WriteInt(kPickleVersion);
|
| + pickle->WriteSize(forms.size());
|
| for (PasswordFormList::const_iterator it = forms.begin() ;
|
| it != forms.end() ; ++it) {
|
| const PasswordForm* form = *it;
|
| pickle->WriteInt(form->scheme);
|
| pickle->WriteString(form->origin.spec());
|
| pickle->WriteString(form->action.spec());
|
| - pickle->WriteWString(form->username_element);
|
| - pickle->WriteWString(form->username_value);
|
| - pickle->WriteWString(form->password_element);
|
| - pickle->WriteWString(form->password_value);
|
| - pickle->WriteWString(form->submit_element);
|
| + pickle->WriteString16(form->username_element);
|
| + pickle->WriteString16(form->username_value);
|
| + pickle->WriteString16(form->password_element);
|
| + pickle->WriteString16(form->password_value);
|
| + pickle->WriteString16(form->submit_element);
|
| pickle->WriteBool(form->ssl_valid);
|
| pickle->WriteBool(form->preferred);
|
| pickle->WriteBool(form->blacklisted_by_user);
|
| + pickle->WriteInt64(form->date_created.ToTimeT());
|
| }
|
| }
|
|
|
| -void PasswordStoreKWallet::DeserializeValue(const PasswordForm& key,
|
| +void PasswordStoreKWallet::DeserializeValue(const string& signon_realm,
|
| const Pickle& pickle,
|
| PasswordFormList* forms) {
|
| void* iter = NULL;
|
|
|
| - int count = 0;
|
| - pickle.ReadInt(&iter, &count);
|
| + int version = -1;
|
| + pickle.ReadInt(&iter, &version);
|
| + if (version != kPickleVersion) {
|
| + // This is the only version so far, so anything else is an error.
|
| + return;
|
| + }
|
|
|
| - for (int i = 0; i < count; ++i) {
|
| + size_t count = 0;
|
| + pickle.ReadSize(&iter, &count);
|
| +
|
| + forms->reserve(forms->size() + count);
|
| + for (size_t i = 0; i < count; ++i) {
|
| PasswordForm* form = new PasswordForm();
|
| - form->signon_realm.assign(key.signon_realm);
|
| + form->signon_realm.assign(signon_realm);
|
|
|
| - pickle.ReadInt(&iter, reinterpret_cast<int*>(&form->scheme));
|
| + int scheme = 0;
|
| + pickle.ReadInt(&iter, &scheme);
|
| + form->scheme = static_cast<PasswordForm::Scheme>(scheme);
|
| ReadGURL(pickle, &iter, &form->origin);
|
| ReadGURL(pickle, &iter, &form->action);
|
| - pickle.ReadWString(&iter, &form->username_element);
|
| - pickle.ReadWString(&iter, &form->username_value);
|
| - pickle.ReadWString(&iter, &form->password_element);
|
| - pickle.ReadWString(&iter, &form->password_value);
|
| - pickle.ReadWString(&iter, &form->submit_element);
|
| + pickle.ReadString16(&iter, &form->username_element);
|
| + pickle.ReadString16(&iter, &form->username_value);
|
| + pickle.ReadString16(&iter, &form->password_element);
|
| + pickle.ReadString16(&iter, &form->password_value);
|
| + pickle.ReadString16(&iter, &form->submit_element);
|
| pickle.ReadBool(&iter, &form->ssl_valid);
|
| pickle.ReadBool(&iter, &form->preferred);
|
| pickle.ReadBool(&iter, &form->blacklisted_by_user);
|
| + int64 date_created = 0;
|
| + pickle.ReadInt64(&iter, &date_created);
|
| + form->date_created = base::Time::FromTimeT(date_created);
|
| forms->push_back(form);
|
| }
|
| }
|
|
|