diff options
author | jeremy@chromium.org <jeremy@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2009-08-21 21:53:54 +0000 |
---|---|---|
committer | jeremy@chromium.org <jeremy@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2009-08-21 21:53:54 +0000 |
commit | 1db97ce76cad4c569c4ae79ad1422620ea5d97cf (patch) | |
tree | e64033813082aaa285af85149d4bdcc01de2317f /chrome | |
parent | c451714f638ec81589602405c45776285f93e9d8 (diff) | |
download | chromium_src-1db97ce76cad4c569c4ae79ad1422620ea5d97cf.zip chromium_src-1db97ce76cad4c569c4ae79ad1422620ea5d97cf.tar.gz chromium_src-1db97ce76cad4c569c4ae79ad1422620ea5d97cf.tar.bz2 |
Recommit "Bring up Firefox Password Import Unittest on OS X."
This recommits r23971
Review URL: http://codereview.chromium.org/174259
git-svn-id: svn://svn.chromium.org/chrome/trunk/src@24024 0039d316-1c4b-4281-b951-d872f2087c98
Diffstat (limited to 'chrome')
27 files changed, 518 insertions, 28 deletions
diff --git a/chrome/browser/importer/firefox3_importer.h b/chrome/browser/importer/firefox3_importer.h index 12a678f..9daa6b53a 100644 --- a/chrome/browser/importer/firefox3_importer.h +++ b/chrome/browser/importer/firefox3_importer.h @@ -80,7 +80,7 @@ class Firefox3Importer : public Importer { std::wstring source_path_; std::wstring app_path_; - DISALLOW_EVIL_CONSTRUCTORS(Firefox3Importer); + DISALLOW_COPY_AND_ASSIGN(Firefox3Importer); }; #endif // CHROME_BROWSER_IMPORTER_FIREFOX3_IMPORTER_H_ diff --git a/chrome/browser/importer/firefox_importer_unittest.cc b/chrome/browser/importer/firefox_importer_unittest.cc index 1c0af23..e7e9470 100644 --- a/chrome/browser/importer/firefox_importer_unittest.cc +++ b/chrome/browser/importer/firefox_importer_unittest.cc @@ -8,46 +8,61 @@ #include "base/file_util.h" #include "base/path_service.h" #include "chrome/browser/importer/firefox2_importer.h" +#include "chrome/browser/importer/firefox_importer_unittest_utils.h" #include "chrome/browser/importer/firefox_importer_utils.h" #include "chrome/browser/importer/nss_decryptor.h" #include "chrome/common/chrome_paths.h" using base::Time; -// TODO(jeremy): Port NSSDecryptor to OSX and enable these tests. -#if !defined(OS_MACOSX) +// The following 2 tests require the use of the NSSDecryptor, on OSX this needs +// to run in a separate process, so we use a proxy object so we can share the +// same test between platforms. TEST(FirefoxImporterTest, Firefox2NSS3Decryptor) { std::wstring nss_path; ASSERT_TRUE(PathService::Get(chrome::DIR_TEST_DATA, &nss_path)); +#ifdef OS_MACOSX + file_util::AppendToPath(&nss_path, L"firefox2_nss_mac"); +#else file_util::AppendToPath(&nss_path, L"firefox2_nss"); +#endif // !OS_MACOSX std::wstring db_path; ASSERT_TRUE(PathService::Get(chrome::DIR_TEST_DATA, &db_path)); file_util::AppendToPath(&db_path, L"firefox2_profile"); - NSSDecryptor decryptor; - EXPECT_TRUE(decryptor.Init(nss_path, db_path)); - EXPECT_EQ(L"hello", decryptor.Decrypt("MDIEEPgAAAAAAAAAAAAAAAAAAAE" + + FFUnitTestDecryptorProxy decryptor_proxy; + ASSERT_TRUE(decryptor_proxy.Setup(nss_path)); + + EXPECT_TRUE(decryptor_proxy.DecryptorInit(nss_path, db_path)); + EXPECT_EQ(L"hello", decryptor_proxy.Decrypt("MDIEEPgAAAAAAAAAAAAAAAAAAAE" "wFAYIKoZIhvcNAwcECBJM63MpT9rtBAjMCm7qo/EhlA==")); // Test UTF-16 encoding. - EXPECT_EQ(L"\x4E2D", decryptor.Decrypt("MDIEEPgAAAAAAAAAAAAAAAAAAAE" + EXPECT_EQ(L"\x4E2D", decryptor_proxy.Decrypt("MDIEEPgAAAAAAAAAAAAAAAAAAAE" "wFAYIKoZIhvcNAwcECN9OQ5ZFmhb8BAiFo1Z+fUvaIQ==")); } TEST(FirefoxImporterTest, Firefox3NSS3Decryptor) { std::wstring nss_path; ASSERT_TRUE(PathService::Get(chrome::DIR_TEST_DATA, &nss_path)); +#ifdef OS_MACOSX + file_util::AppendToPath(&nss_path, L"firefox3_nss_mac"); +#else file_util::AppendToPath(&nss_path, L"firefox3_nss"); +#endif // !OS_MACOSX std::wstring db_path; ASSERT_TRUE(PathService::Get(chrome::DIR_TEST_DATA, &db_path)); file_util::AppendToPath(&db_path, L"firefox3_profile"); - NSSDecryptor decryptor; - EXPECT_TRUE(decryptor.Init(nss_path, db_path)); - EXPECT_EQ(L"hello", decryptor.Decrypt("MDIEEPgAAAAAAAAAAAAAAAAAAAE" + + FFUnitTestDecryptorProxy decryptor_proxy; + ASSERT_TRUE(decryptor_proxy.Setup(nss_path)); + + EXPECT_TRUE(decryptor_proxy.DecryptorInit(nss_path, db_path)); + EXPECT_EQ(L"hello", decryptor_proxy.Decrypt("MDIEEPgAAAAAAAAAAAAAAAAAAAE" "wFAYIKoZIhvcNAwcECKajtRg4qFSHBAhv9luFkXgDJA==")); // Test UTF-16 encoding. - EXPECT_EQ(L"\x4E2D", decryptor.Decrypt("MDIEEPgAAAAAAAAAAAAAAAAAAAE" + EXPECT_EQ(L"\x4E2D", decryptor_proxy.Decrypt("MDIEEPgAAAAAAAAAAAAAAAAAAAE" "wFAYIKoZIhvcNAwcECLWqqiccfQHWBAie74hxnULxlw==")); } -#endif // !OS_MACOSX TEST(FirefoxImporterTest, Firefox2BookmarkParse) { bool result; diff --git a/chrome/browser/importer/firefox_importer_unittest_messages_internal.h b/chrome/browser/importer/firefox_importer_unittest_messages_internal.h new file mode 100644 index 0000000..72eff6f --- /dev/null +++ b/chrome/browser/importer/firefox_importer_unittest_messages_internal.h @@ -0,0 +1,33 @@ +// Copyright (c) 2009 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. + +// This header is meant to be included in multiple passes, hence no traditional +// header guard. +// See ipc_message_macros.h for explanation of the macros and passes. + +#include "ipc/ipc_message_macros.h" + +// Messages definitions for messages sent between the unit test binary and +// a child process by FFUnitTestDecryptorProxy. +IPC_BEGIN_MESSAGES(Test) + +// Server->Child: Initialize the decrytor with the following paramters. +IPC_MESSAGE_CONTROL2(Msg_Decryptor_Init, + std::wstring /* dll_path */, + std::wstring /* db_path */) +// Child->Server: Return paramter from init call. +IPC_MESSAGE_CONTROL1(Msg_Decryptor_InitReturnCode, + bool /* ret */) + +// Server->Child: Decrypt a given string. +IPC_MESSAGE_CONTROL1(Msg_Decrypt, + std::string /* crypt */) +// Child->Server: Decrypted String. +IPC_MESSAGE_CONTROL1(Msg_Decryptor_Response, + std::wstring /* unencrypted_str */) + +// Server->Child: Die. +IPC_MESSAGE_CONTROL0(Msg_Decryptor_Quit) + +IPC_END_MESSAGES(Test) diff --git a/chrome/browser/importer/firefox_importer_unittest_utils.h b/chrome/browser/importer/firefox_importer_unittest_utils.h new file mode 100644 index 0000000..cb53cce --- /dev/null +++ b/chrome/browser/importer/firefox_importer_unittest_utils.h @@ -0,0 +1,84 @@ +// Copyright (c) 2009 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. + +#ifndef CHROME_BROWSER_IMPORTER_FIREFOX_IMPORTER_UNITTEST_UTILS_H_ +#define CHROME_BROWSER_IMPORTER_FIREFOX_IMPORTER_UNITTEST_UTILS_H_ + +#include "base/basictypes.h" +#include "base/process_util.h" +#include "base/scoped_ptr.h" +#include "chrome/browser/importer/nss_decryptor.h" + +class FFDecryptorServerChannelListener; +namespace IPC { + class Channel; +} // namespace IPC +class MessageLoopForIO; + +// On OS X NSSDecryptor needs to run in a separate process. To allow us to use +// the same unit test on all platforms we use a proxy class which spawns a +// child process to do decryption on OS X, and calls through directly +// to NSSDecryptor on other platforms. +// On OS X: +// 2 IPC messages are sent for every method of NSSDecryptor, one containing the +// input arguments sent from Server->Child and one coming back containing +// the return argument e.g. +// +// -> Msg_Decryptor_Init(dll_path, db_path) +// <- Msg_Decryptor_InitReturnCode(bool) +class FFUnitTestDecryptorProxy { + public: + FFUnitTestDecryptorProxy(); + virtual ~FFUnitTestDecryptorProxy(); + + // Initialize a decryptor, returns true if the object was + // constructed successfully. + bool Setup(std::wstring& nss_path); + + // This match the parallel functions in NSSDecryptor. + bool DecryptorInit(const std::wstring& dll_path, const std::wstring& db_path); + std::wstring Decrypt(const std::string& crypt); + + private: +#if defined(OS_MACOSX) + // Blocks until either a timeout is reached, or until the client process + // responds to an IPC message. + // Returns true if a reply was recieved successfully and false if the + // the operation timed out. + bool WaitForClientResponse(); + + base::ProcessHandle child_process_; + scoped_ptr<IPC::Channel> channel_; + scoped_ptr<FFDecryptorServerChannelListener> listener_; + scoped_ptr<MessageLoopForIO> message_loop_; +#else + NSSDecryptor decryptor_; +#endif // !OS_MACOSX + DISALLOW_COPY_AND_ASSIGN(FFUnitTestDecryptorProxy); +}; + +// On Non-OSX platforms FFUnitTestDecryptorProxy simply calls through to +// NSSDecryptor. +#if !defined(OS_MACOSX) +FFUnitTestDecryptorProxy::FFUnitTestDecryptorProxy() { +} + +FFUnitTestDecryptorProxy::~FFUnitTestDecryptorProxy() { +} + +bool FFUnitTestDecryptorProxy::Setup(std::wstring& /* nss_path */) { + return true; +} + +bool FFUnitTestDecryptorProxy::DecryptorInit(const std::wstring& dll_path, + const std::wstring& db_path) { + return decryptor_.Init(dll_path, db_path); +} + +std::wstring FFUnitTestDecryptorProxy::Decrypt(const std::string& crypt) { + return decryptor_.Decrypt(crypt); +} +#endif // !OS_MACOSX + +#endif // CHROME_BROWSER_IMPORTER_FIREFOX_IMPORTER_UNITTEST_UTILS_H_ diff --git a/chrome/browser/importer/firefox_importer_unittest_utils_mac.cc b/chrome/browser/importer/firefox_importer_unittest_utils_mac.cc new file mode 100644 index 0000000..d44b336 --- /dev/null +++ b/chrome/browser/importer/firefox_importer_unittest_utils_mac.cc @@ -0,0 +1,266 @@ +// Copyright (c) 2009 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. + +#include "chrome/browser/importer/firefox_importer_unittest_utils.h" + +#include "base/command_line.h" +#include "base/debug_on_start.h" +#include "base/file_path.h" +#include "base/message_loop.h" +#include "chrome/browser/importer/firefox_importer_utils.h" +#include "ipc/ipc_channel.h" +#include "ipc/ipc_descriptors.h" +#include "ipc/ipc_message.h" +#include "ipc/ipc_message_utils.h" +#include "ipc/ipc_switches.h" +#include "testing/multiprocess_func_list.h" + +// Definition of IPC Messages used for this test. +#define MESSAGES_INTERNAL_FILE \ + "chrome/browser/importer/firefox_importer_unittest_messages_internal.h" +#include "ipc/ipc_message_macros.h" + +namespace { + +// Name of IPC Channel to use for Server<-> Child Communications. +const char kTestChannelID[] = "T1"; + +// Launch the child process: +// |nss_path| - path to the NSS directory holding the decryption libraries. +// |channel| - IPC Channel to use for communication. +// |handle| - On return, the process handle to use to communicate with the +// child. +bool LaunchNSSDecrypterChildProcess(const std::wstring& nss_path, + const IPC::Channel& channel, base::ProcessHandle* handle) { + CommandLine cl(*CommandLine::ForCurrentProcess()); + cl.AppendSwitchWithValue(L"client", L"NSSDecrypterChildProcess"); + + FilePath ff_dylib_dir = FilePath::FromWStringHack(nss_path); + // Set env variable needed for FF encryption libs to load. + // See "chrome/browser/importer/nss_decryptor_mac.mm" for an explanation of + // why we need this. + base::environment_vector env; + std::pair<const char*,const char*> dyld_override; + dyld_override.first = "DYLD_FALLBACK_LIBRARY_PATH"; + dyld_override.second = ff_dylib_dir.value().c_str(); + env.push_back(dyld_override); + + base::file_handle_mapping_vector fds_to_map; + const int ipcfd = channel.GetClientFileDescriptor(); + if (ipcfd > -1) { + fds_to_map.push_back(std::pair<int,int>(ipcfd, kPrimaryIPCChannel + 3)); + } else { + return false; + } + + bool debug_on_start = CommandLine::ForCurrentProcess()->HasSwitch( + switches::kDebugChildren); + return base::LaunchApp(cl.argv(), env, fds_to_map, debug_on_start, + handle); +} + +} // namespace + +//----------------------- Server -------------------- + +// Class to communicate on the server side of the IPC Channel. +// Method calls are sent over IPC and replies are read back into class +// variables. +// This class needs to be called on a single thread. +class FFDecryptorServerChannelListener : public IPC::Channel::Listener { + public: + FFDecryptorServerChannelListener() + : got_result(false), sender_(NULL) {} + + void SetSender(IPC::Message::Sender* sender) { + sender_ = sender; + } + + void OnInitDecryptorResponse(bool result) { + DCHECK(!got_result); + result_bool = result; + got_result = true; + MessageLoop::current()->Quit(); + } + + void OnDecryptedTextResonse(std::wstring decrypted_text) { + DCHECK(!got_result); + result_string = decrypted_text; + got_result = true; + MessageLoop::current()->Quit(); + } + + void QuitClient() { + if (sender_) + sender_->Send(new Msg_Decryptor_Quit()); + } + + virtual void OnMessageReceived(const IPC::Message& msg) { + IPC_BEGIN_MESSAGE_MAP(FFDecryptorServerChannelListener, msg) + IPC_MESSAGE_HANDLER(Msg_Decryptor_InitReturnCode, OnInitDecryptorResponse) + IPC_MESSAGE_HANDLER(Msg_Decryptor_Response, OnDecryptedTextResonse) + IPC_END_MESSAGE_MAP() + } + + // If an error occured, just kill the message Loop. + virtual void OnChannelError() { + got_result = false; + MessageLoop::current()->Quit(); + } + + // Results of IPC calls. + std::wstring result_string; + bool result_bool; + // True if IPC call succeeded and data in above variables is valid. + bool got_result; + + private: + IPC::Message::Sender* sender_; // weak +}; + +FFUnitTestDecryptorProxy::FFUnitTestDecryptorProxy() + : child_process_(0) { +} + +bool FFUnitTestDecryptorProxy::Setup(std::wstring& nss_path) { + // Create a new message loop and spawn the child process. + message_loop_.reset(new MessageLoopForIO()); + + listener_.reset(new FFDecryptorServerChannelListener()); + channel_.reset(new IPC::Channel(kTestChannelID, + IPC::Channel::MODE_SERVER, + listener_.get())); + channel_->Connect(); + listener_->SetSender(channel_.get()); + + // Spawn child and set up sync IPC connection. + bool ret = LaunchNSSDecrypterChildProcess(nss_path, + *(channel_.get()), + &child_process_); + return ret && (child_process_ != 0); +} + +FFUnitTestDecryptorProxy::~FFUnitTestDecryptorProxy() { + listener_->QuitClient(); + channel_->Close(); + + if (child_process_) { + base::WaitForSingleProcess(child_process_, 5000); + base::CloseProcessHandle(child_process_); + } +} + +// A message_loop task that quits the message loop when invoked, setting cancel +// causes the task to do nothing when invoked. +class CancellableQuitMsgLoop : public base::RefCounted<CancellableQuitMsgLoop> { + public: + CancellableQuitMsgLoop() : cancelled_(false) {} + void QuitNow() { + if (!cancelled_) + MessageLoop::current()->Quit(); + } + bool cancelled_; +}; + +// Spin until either a client response arrives or a timeout occurs. +bool FFUnitTestDecryptorProxy::WaitForClientResponse() { + const int64 kLoopTimeoutMS = 10 * 1000; // 10 seconds. + + // What we're trying to do here is to wait for an RPC message to go over the + // wire and the client to reply. If the client does not replyy by a given + // timeout we kill the message loop. + // The way we do this is to post a CancellableQuitMsgLoop for 3 seconds in + // the future and cancel it if an RPC message comes back earlier. + // This relies on the IPC listener class to quit the message loop itself when + // a message comes in. + scoped_refptr<CancellableQuitMsgLoop> quit_task = + new CancellableQuitMsgLoop(); + MessageLoop::current()->PostDelayedTask(FROM_HERE, NewRunnableMethod( + quit_task.get(), &CancellableQuitMsgLoop::QuitNow), kLoopTimeoutMS); + + message_loop_->Run(); + bool ret = !quit_task->cancelled_; + quit_task->cancelled_ = false; + return ret; +} + +bool FFUnitTestDecryptorProxy::DecryptorInit(const std::wstring& dll_path, + const std::wstring& db_path) { + channel_->Send(new Msg_Decryptor_Init(dll_path, db_path)); + bool ok = WaitForClientResponse(); + if (ok && listener_->got_result) { + listener_->got_result = false; + return listener_->result_bool; + } + return false; +} + +std::wstring FFUnitTestDecryptorProxy::Decrypt(const std::string& crypt) { + channel_->Send(new Msg_Decrypt(crypt)); + bool ok = WaitForClientResponse(); + if (ok && listener_->got_result) { + listener_->got_result = false; + return listener_->result_string; + } + return L""; +} + +//---------------------------- Child Process ----------------------- + +// Class to listen on the client side of the ipc channel, it calls through +// to the NSSDecryptor and sends back a reply. +class FFDecryptorClientChannelListener : public IPC::Channel::Listener { + public: + FFDecryptorClientChannelListener() + : sender_(NULL) {} + + void SetSender(IPC::Message::Sender* sender) { + sender_ = sender; + } + + void OnDecryptor_Init(std::wstring dll_path, std::wstring db_path) { + bool ret = decryptor_.Init(dll_path, db_path); + sender_->Send(new Msg_Decryptor_InitReturnCode(ret)); + } + + void OnDecrypt(std::string crypt) { + std::wstring unencrypted_str = decryptor_.Decrypt(crypt); + sender_->Send(new Msg_Decryptor_Response(unencrypted_str)); + } + + void OnQuitRequest() { + MessageLoop::current()->Quit(); + } + + virtual void OnMessageReceived(const IPC::Message& msg) { + IPC_BEGIN_MESSAGE_MAP(FFDecryptorClientChannelListener, msg) + IPC_MESSAGE_HANDLER(Msg_Decryptor_Init, OnDecryptor_Init) + IPC_MESSAGE_HANDLER(Msg_Decrypt, OnDecrypt) + IPC_MESSAGE_HANDLER(Msg_Decryptor_Quit, OnQuitRequest) + IPC_END_MESSAGE_MAP() + } + + virtual void OnChannelError() { + MessageLoop::current()->Quit(); + } + + private: + NSSDecryptor decryptor_; + IPC::Message::Sender* sender_; +}; + +// Entry function in child process. +MULTIPROCESS_TEST_MAIN(NSSDecrypterChildProcess) { + MessageLoopForIO main_message_loop; + FFDecryptorClientChannelListener listener; + + IPC::Channel channel(kTestChannelID, IPC::Channel::MODE_CLIENT, &listener); + channel.Connect(); + listener.SetSender(&channel); + + // run message loop + MessageLoop::current()->Run(); + + return 0; +} diff --git a/chrome/browser/importer/firefox_importer_utils.h b/chrome/browser/importer/firefox_importer_utils.h index 41b88fa..fa7e50b 100644 --- a/chrome/browser/importer/firefox_importer_utils.h +++ b/chrome/browser/importer/firefox_importer_utils.h @@ -25,7 +25,16 @@ int GetCurrentFirefoxMajorVersionFromRegistry(); // Detects where Firefox lives. Returns a empty string if Firefox // is not installed. std::wstring GetFirefoxInstallPathFromRegistry(); -#endif +#endif // OS_WIN + +#if defined(OS_MACOSX) + +// Get the directory in which the Firefox .dylibs live, we need to load these +// in order to decoded FF profile passwords. +// The Path is usuall FF App Bundle/Contents/Mac OS/ +// Returns empty path on failure. +FilePath GetFirefoxDylibPath(); +#endif // OS_MACOSX // Detects version of Firefox and installation path from given Firefox profile bool GetFirefoxVersionAndPathFromProfile(const std::wstring& profile_path, diff --git a/chrome/browser/importer/firefox_importer_utils_mac.mm b/chrome/browser/importer/firefox_importer_utils_mac.mm index 5fd24b0..bea6b71 100644 --- a/chrome/browser/importer/firefox_importer_utils_mac.mm +++ b/chrome/browser/importer/firefox_importer_utils_mac.mm @@ -23,9 +23,27 @@ FilePath GetProfilesINI() { ini_file = FilePath([profiles_ini fileSystemRepresentation]); } } - + if (file_util::PathExists(ini_file)) return ini_file; return FilePath(); } + +FilePath GetFirefoxDylibPath() { + CFURLRef appURL = nil; + if (LSFindApplicationForInfo(kLSUnknownCreator, + CFSTR("org.mozilla.firefox"), + NULL, + NULL, + &appURL) != noErr) { + return FilePath(); + } + NSBundle *ff_bundle = [NSBundle + bundleWithPath:[reinterpret_cast<const NSURL*>(appURL) path]]; + CFRelease(appURL); + NSString *ff_library_path = [[ff_bundle executablePath] + stringByDeletingLastPathComponent]; + + return FilePath([ff_library_path fileSystemRepresentation]); +} diff --git a/chrome/browser/importer/nss_decryptor_mac.h b/chrome/browser/importer/nss_decryptor_mac.h index 1eaf109..477cf53 100644 --- a/chrome/browser/importer/nss_decryptor_mac.h +++ b/chrome/browser/importer/nss_decryptor_mac.h @@ -114,9 +114,8 @@ class NSSDecryptor { : NSS_Init(NULL), NSS_Shutdown(NULL), PK11_GetInternalKeySlot(NULL), PK11_CheckUserPassword(NULL), PK11_FreeSlot(NULL), PK11_Authenticate(NULL), PK11SDR_Decrypt(NULL), SECITEM_FreeItem(NULL), - PL_ArenaFinish(NULL), PR_Cleanup(NULL), is_nss_initialized_(false) {} - ~NSSDecryptor() {} + ~NSSDecryptor(); // Initializes NSS if it hasn't already been initialized. bool Init(const std::wstring& /* dll_path */, @@ -150,14 +149,9 @@ class NSSDecryptor { PK11AuthenticateFunc PK11_Authenticate; PK11SDRDecryptFunc PK11SDR_Decrypt; SECITEMFreeItemFunc SECITEM_FreeItem; - PLArenaFinishFunc PL_ArenaFinish; - PRCleanupFunc PR_Cleanup; // Libraries necessary for decrypting the passwords. static const wchar_t kNSS3Library[]; - static const wchar_t kSoftokn3Library[]; - static const wchar_t kPLDS4Library[]; - static const wchar_t kNSPR4Library[]; // True if NSS_Init() has been called bool is_nss_initialized_; diff --git a/chrome/browser/importer/nss_decryptor_mac.mm b/chrome/browser/importer/nss_decryptor_mac.mm index 97e85b6..dc6dd0d 100644 --- a/chrome/browser/importer/nss_decryptor_mac.mm +++ b/chrome/browser/importer/nss_decryptor_mac.mm @@ -4,20 +4,68 @@ #include <Cocoa/Cocoa.h> +#include <dlfcn.h> + +#include "base/sys_string_conversions.h" + #include "chrome/browser/importer/nss_decryptor_mac.h" +#include "chrome/browser/importer/firefox_importer_utils.h" #include "base/logging.h" // static const wchar_t NSSDecryptor::kNSS3Library[] = L"libnss3.dylib"; -const wchar_t NSSDecryptor::kSoftokn3Library[] = L"libsoftokn3.dylib"; -const wchar_t NSSDecryptor::kPLDS4Library[] = L"libplds4.dylib"; -const wchar_t NSSDecryptor::kNSPR4Library[] = L"libnspr4.dylib"; +// Important!! : On OS X the nss3 libraries are compiled with depedencies +// on one another, referenced using dyld's @executable_path directive. +// To make a long story short in order to get the libraries to load, dyld's +// fallback path needs to be set to the directory containing the libraries. +// To do so, the process this function runs in must have the +// DYLD_FALLBACK_LIBRARY_PATH set on startup to said directory. bool NSSDecryptor::Init(const std::wstring& dll_path, const std::wstring& db_path) { - // TODO(port): Load the NSS libraries and call InitNSS() - // http://code.google.com/p/chromium/issues/detail?id=15455 - NOTIMPLEMENTED(); - return false; + FilePath dylib_file_path = FilePath::FromWStringHack(dll_path); + FilePath nss3_path = dylib_file_path.Append("libnss3.dylib"); + + void *nss_3_lib = dlopen(nss3_path.value().c_str(), RTLD_LAZY); + if (!nss_3_lib) { + LOG(ERROR) << "Failed to load nss3 lib" << dlerror(); + return false; + } + + NSS_Init = (NSSInitFunc)dlsym(nss_3_lib, "NSS_Init"); + NSS_Shutdown = (NSSShutdownFunc)dlsym(nss_3_lib, "NSS_Shutdown"); + PK11_GetInternalKeySlot = + (PK11GetInternalKeySlotFunc)dlsym(nss_3_lib, "PK11_GetInternalKeySlot"); + PK11_CheckUserPassword = + (PK11CheckUserPasswordFunc)dlsym(nss_3_lib, "PK11_CheckUserPassword"); + PK11_FreeSlot = (PK11FreeSlotFunc)dlsym(nss_3_lib, "PK11_FreeSlot"); + PK11_Authenticate = + (PK11AuthenticateFunc)dlsym(nss_3_lib, "PK11_Authenticate"); + PK11SDR_Decrypt = (PK11SDRDecryptFunc)dlsym(nss_3_lib, "PK11SDR_Decrypt"); + SECITEM_FreeItem = (SECITEMFreeItemFunc)dlsym(nss_3_lib, "SECITEM_FreeItem"); + + if (!NSS_Init || !NSS_Shutdown || !PK11_GetInternalKeySlot || + !PK11_CheckUserPassword || !PK11_FreeSlot || !PK11_Authenticate || + !PK11SDR_Decrypt || !SECITEM_FreeItem) { + LOG(ERROR) << "NSS3 importer couldn't find entry points"; + return false; + } + + SECStatus result = NSS_Init(base::SysWideToNativeMB(db_path).c_str()); + + if (result != SECSuccess) { + LOG(ERROR) << "NSS_Init Failed returned: " << result; + return false; + } + + is_nss_initialized_ = true; + return true; +} + +NSSDecryptor::~NSSDecryptor() { + if (NSS_Shutdown && is_nss_initialized_) { + NSS_Shutdown(); + is_nss_initialized_ = false; + } } diff --git a/chrome/chrome.gyp b/chrome/chrome.gyp index 2bfba7d..c4f600e 100644 --- a/chrome/chrome.gyp +++ b/chrome/chrome.gyp @@ -3940,7 +3940,10 @@ 'browser/history/url_database_unittest.cc', 'browser/history/visit_database_unittest.cc', 'browser/history/visit_tracker_unittest.cc', + 'browser/importer/firefox_importer_unittest_messages_internal.h', 'browser/importer/firefox_importer_unittest.cc', + 'browser/importer/firefox_importer_unittest_utils.h', + 'browser/importer/firefox_importer_unittest_utils_mac.cc', 'browser/importer/importer_unittest.cc', 'browser/importer/safari_importer_unittest.mm', 'browser/importer/toolbar_importer_unittest.cc', diff --git a/chrome/test/data/firefox2_nss_mac/README b/chrome/test/data/firefox2_nss_mac/README new file mode 100644 index 0000000..74e6b27 --- /dev/null +++ b/chrome/test/data/firefox2_nss_mac/README @@ -0,0 +1,7 @@ +The NSPR and NSS DLLs in this directory (libnspr4.dylib, libnssdbm3.dylib, libplc4.dylib, libsoftokn3.dylib +libfreebl3.dylib, libnss3.dylib, libnssutil3.dylib, libplds4.dylib, libsqlite3.dylib) come from the Firefox 2.0.0.20 +distribution for OS X. + +The source code of NSPR and NSS, which you may use, modify, and distribute, is +available to you free-of-charge from www.mozilla.org under the Mozilla Public +License and other open source software licenses. diff --git a/chrome/test/data/firefox2_nss_mac/libfreebl3.dylib b/chrome/test/data/firefox2_nss_mac/libfreebl3.dylib Binary files differnew file mode 100755 index 0000000..1eb3bc9 --- /dev/null +++ b/chrome/test/data/firefox2_nss_mac/libfreebl3.dylib diff --git a/chrome/test/data/firefox2_nss_mac/libnspr4.dylib b/chrome/test/data/firefox2_nss_mac/libnspr4.dylib Binary files differnew file mode 100755 index 0000000..7d1653f --- /dev/null +++ b/chrome/test/data/firefox2_nss_mac/libnspr4.dylib diff --git a/chrome/test/data/firefox2_nss_mac/libnss3.dylib b/chrome/test/data/firefox2_nss_mac/libnss3.dylib Binary files differnew file mode 100755 index 0000000..4406d2a --- /dev/null +++ b/chrome/test/data/firefox2_nss_mac/libnss3.dylib diff --git a/chrome/test/data/firefox2_nss_mac/libplc4.dylib b/chrome/test/data/firefox2_nss_mac/libplc4.dylib Binary files differnew file mode 100755 index 0000000..642f84e --- /dev/null +++ b/chrome/test/data/firefox2_nss_mac/libplc4.dylib diff --git a/chrome/test/data/firefox2_nss_mac/libplds4.dylib b/chrome/test/data/firefox2_nss_mac/libplds4.dylib Binary files differnew file mode 100755 index 0000000..7d932a4 --- /dev/null +++ b/chrome/test/data/firefox2_nss_mac/libplds4.dylib diff --git a/chrome/test/data/firefox2_nss_mac/libsoftokn3.dylib b/chrome/test/data/firefox2_nss_mac/libsoftokn3.dylib Binary files differnew file mode 100755 index 0000000..de32c01 --- /dev/null +++ b/chrome/test/data/firefox2_nss_mac/libsoftokn3.dylib diff --git a/chrome/test/data/firefox3_nss_mac/README b/chrome/test/data/firefox3_nss_mac/README new file mode 100644 index 0000000..b54a99e --- /dev/null +++ b/chrome/test/data/firefox3_nss_mac/README @@ -0,0 +1,13 @@ +The NSPR and NSS DLLs in this directory (mozcrt19.dll, nss3.dll, nssutil3.dll +plds4.dll, sqlite3.dll, freebl3.dll, nspr4.dll, nssdbm3.dll, plc4.dll, and +softokn3.dll) come from the Firefox 3.0 distribution for Windows. + +The source code of NSPR and NSS, which you may use, modify, and distribute, is +available to you free-of-charge from www.mozilla.org under the Mozilla Public +License and other open source software licenses. + +The source code of sqlite3.dll is in the public domain. + +mozcrt19.dll is the Mozilla Custom C Runtime, in which Mozilla replaced the +default allocator with jemalloc. mozcrt19.dll is distributed in the object +code form only and as part of the NSPR and NSS DLLs. diff --git a/chrome/test/data/firefox3_nss_mac/libfreebl3.dylib b/chrome/test/data/firefox3_nss_mac/libfreebl3.dylib Binary files differnew file mode 100755 index 0000000..702d231 --- /dev/null +++ b/chrome/test/data/firefox3_nss_mac/libfreebl3.dylib diff --git a/chrome/test/data/firefox3_nss_mac/libnspr4.dylib b/chrome/test/data/firefox3_nss_mac/libnspr4.dylib Binary files differnew file mode 100755 index 0000000..5484689 --- /dev/null +++ b/chrome/test/data/firefox3_nss_mac/libnspr4.dylib diff --git a/chrome/test/data/firefox3_nss_mac/libnss3.dylib b/chrome/test/data/firefox3_nss_mac/libnss3.dylib Binary files differnew file mode 100755 index 0000000..d18c65c --- /dev/null +++ b/chrome/test/data/firefox3_nss_mac/libnss3.dylib diff --git a/chrome/test/data/firefox3_nss_mac/libnssdbm3.dylib b/chrome/test/data/firefox3_nss_mac/libnssdbm3.dylib Binary files differnew file mode 100755 index 0000000..e7f7cb7 --- /dev/null +++ b/chrome/test/data/firefox3_nss_mac/libnssdbm3.dylib diff --git a/chrome/test/data/firefox3_nss_mac/libnssutil3.dylib b/chrome/test/data/firefox3_nss_mac/libnssutil3.dylib Binary files differnew file mode 100755 index 0000000..0e6e48f --- /dev/null +++ b/chrome/test/data/firefox3_nss_mac/libnssutil3.dylib diff --git a/chrome/test/data/firefox3_nss_mac/libplc4.dylib b/chrome/test/data/firefox3_nss_mac/libplc4.dylib Binary files differnew file mode 100755 index 0000000..e5bf110 --- /dev/null +++ b/chrome/test/data/firefox3_nss_mac/libplc4.dylib diff --git a/chrome/test/data/firefox3_nss_mac/libplds4.dylib b/chrome/test/data/firefox3_nss_mac/libplds4.dylib Binary files differnew file mode 100755 index 0000000..fc65226 --- /dev/null +++ b/chrome/test/data/firefox3_nss_mac/libplds4.dylib diff --git a/chrome/test/data/firefox3_nss_mac/libsoftokn3.dylib b/chrome/test/data/firefox3_nss_mac/libsoftokn3.dylib Binary files differnew file mode 100755 index 0000000..91a3b81 --- /dev/null +++ b/chrome/test/data/firefox3_nss_mac/libsoftokn3.dylib diff --git a/chrome/test/data/firefox3_nss_mac/libsqlite3.dylib b/chrome/test/data/firefox3_nss_mac/libsqlite3.dylib Binary files differnew file mode 100755 index 0000000..4f6d5eb --- /dev/null +++ b/chrome/test/data/firefox3_nss_mac/libsqlite3.dylib |