diff --git a/toolkit/components/places/src/Helpers.cpp b/toolkit/components/places/src/Helpers.cpp index f43daf765334..cc3d88478547 100644 --- a/toolkit/components/places/src/Helpers.cpp +++ b/toolkit/components/places/src/Helpers.cpp @@ -38,8 +38,8 @@ #include "Helpers.h" #include "mozIStorageError.h" -#include "nsIRandomGenerator.h" #include "plbase64.h" +#include "prio.h" #include "nsString.h" #include "nsNavHistory.h" @@ -256,6 +256,45 @@ Base64urlEncode(const PRUint8* aBytes, return NS_OK; } +#ifdef XP_WIN +// Included here because windows.h conflicts with the use of mozIStorageError +// above. +#include +#include +#endif + +static +nsresult +GenerateRandomBytes(PRUint32 aSize, + PRUint8* _buffer) +{ + // On Windows, we'll use its built-in cryptographic API. +#if defined(XP_WIN) + HCRYPTPROV cryptoProvider; + BOOL rc = CryptAcquireContext(&cryptoProvider, 0, 0, PROV_RSA_FULL, + CRYPT_VERIFYCONTEXT | CRYPT_SILENT); + if (rc) { + rc = CryptGenRandom(cryptoProvider, aSize, _buffer); + } + (void)CryptReleaseContext(cryptoProvider, 0); + return rc ? NS_OK : NS_ERROR_FAILURE; + + // On Unix, we'll just read in from /dev/urandom. +#elif defined(XP_UNIX) + NS_ENSURE_ARG_MAX(aSize, PR_INT32_MAX); + PRFileDesc* urandom = PR_Open("/dev/urandom", PR_RDONLY, 0); + nsresult rv = NS_ERROR_FAILURE; + if (urandom) { + PRInt32 bytesRead = PR_Read(urandom, _buffer, aSize); + if (bytesRead == static_cast(aSize)) { + rv = NS_OK; + } + (void)PR_Close(urandom); + } + return rv; +#endif +} + nsresult GenerateGUID(nsCString& _guid) { @@ -266,16 +305,11 @@ GenerateGUID(nsCString& _guid) const PRUint32 kRequiredBytesLength = static_cast(GUID_LENGTH / 4 * 3); - nsCOMPtr rg = - do_GetService("@mozilla.org/security/random-generator;1"); - NS_ENSURE_STATE(rg); - - PRUint8* buffer; - nsresult rv = rg->GenerateRandomBytes(kRequiredBytesLength, &buffer); + PRUint8 buffer[kRequiredBytesLength]; + nsresult rv = GenerateRandomBytes(kRequiredBytesLength, buffer); NS_ENSURE_SUCCESS(rv, rv); rv = Base64urlEncode(buffer, kRequiredBytesLength, _guid); - NS_Free(buffer); NS_ENSURE_SUCCESS(rv, rv); NS_ASSERTION(_guid.Length() == GUID_LENGTH, "GUID is not the right size!"); diff --git a/toolkit/components/places/src/SQLFunctions.cpp b/toolkit/components/places/src/SQLFunctions.cpp index 3fe59032fefe..dae2104faf8c 100644 --- a/toolkit/components/places/src/SQLFunctions.cpp +++ b/toolkit/components/places/src/SQLFunctions.cpp @@ -48,7 +48,6 @@ #include "nsINavHistoryService.h" #include "nsPrintfCString.h" #include "nsNavHistory.h" -#include "nsIRandomGenerator.h" using namespace mozilla::storage; @@ -597,13 +596,6 @@ namespace places { nsresult GenerateGUIDFunction::create(mozIStorageConnection *aDBConn) { - // We need this service to be initialized on the main thread because it is - // not threadsafe. We are about to use it asynchronously, so initialize it - // now. - nsCOMPtr rg = - do_GetService("@mozilla.org/security/random-generator;1"); - NS_ENSURE_STATE(rg); - nsCOMPtr function = new GenerateGUIDFunction(); nsresult rv = aDBConn->CreateFunction( NS_LITERAL_CSTRING("generate_guid"), 0, function diff --git a/toolkit/components/places/tests/unit/test_sql_guid_functions.js b/toolkit/components/places/tests/unit/test_sql_guid_functions.js index ad4d6eaf12cb..0e4ed7243b1f 100644 --- a/toolkit/components/places/tests/unit/test_sql_guid_functions.js +++ b/toolkit/components/places/tests/unit/test_sql_guid_functions.js @@ -29,22 +29,29 @@ function test_guid_invariants() const kAllowedChars = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789-_" do_check_eq(kAllowedChars.length, kExpectedChars); - let checkedChars = {}; - for (let i = 0; i < kAllowedChars; i++) { - checkedChars[kAllowedChars[i]] = false; + const kGuidLength = 12; + + let checkedChars = []; + for (let i = 0; i < kGuidLength; i++) { + checkedChars[i] = {}; + for (let j = 0; j < kAllowedChars; j++) { + checkedChars[i][kAllowedChars[j]] = false; + } } - // We run this until we've seen every character that we expect to see. + // We run this until we've seen every character that we expect to see in every + // position. let seenChars = 0; let stmt = DBConn().createStatement("SELECT GENERATE_GUID()"); - while (seenChars != kExpectedChars) { + while (seenChars != (kExpectedChars * kGuidLength)) { do_check_true(stmt.executeStep()); let guid = stmt.getString(0); check_invariants(guid); for (let i = 0; i < guid.length; i++) { - if (!checkedChars[guid[i]]) { - checkedChars[guid[i]] = true; + let character = guid[i]; + if (!checkedChars[i][character]) { + checkedChars[i][character] = true; seenChars++; } } @@ -53,8 +60,10 @@ function test_guid_invariants() stmt.finalize(); // One last reality check - make sure all of our characters were seen. - for (let i = 0; i < kAllowedChars; i++) { - do_check_true(checkedChars[kAllowedChars[i]]); + for (let i = 0; i < kGuidLength; i++) { + for (let j = 0; j < kAllowedChars; j++) { + do_check_true(checkedChars[i][kAllowedChars[j]]); + } } run_next_test();