1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 1.2 +++ b/toolkit/components/downloads/SQLFunctions.cpp Wed Dec 31 06:09:35 2014 +0100 1.3 @@ -0,0 +1,148 @@ 1.4 +/* vim: sw=2 ts=2 et lcs=trail\:.,tab\:>~ : 1.5 + * This Source Code Form is subject to the terms of the Mozilla Public 1.6 + * License, v. 2.0. If a copy of the MPL was not distributed with this 1.7 + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ 1.8 + 1.9 +#include "mozilla/storage.h" 1.10 +#include "mozilla/storage/Variant.h" 1.11 +#include "mozilla/mozalloc.h" 1.12 +#include "nsString.h" 1.13 +#include "SQLFunctions.h" 1.14 +#include "nsUTF8Utils.h" 1.15 +#include "plbase64.h" 1.16 +#include "prio.h" 1.17 + 1.18 +// The length of guids that are used by the download manager 1.19 +#define GUID_LENGTH 12 1.20 + 1.21 +namespace mozilla { 1.22 +namespace downloads { 1.23 + 1.24 +// Keep this file in sync with the GUID-related code in toolkit/places/SQLFunctions.cpp 1.25 +// and toolkit/places/Helpers.cpp! 1.26 + 1.27 +//////////////////////////////////////////////////////////////////////////////// 1.28 +//// GUID Creation Function 1.29 + 1.30 +////////////////////////////////////////////////////////////////////////////// 1.31 +//// GenerateGUIDFunction 1.32 + 1.33 +/* static */ 1.34 +nsresult 1.35 +GenerateGUIDFunction::create(mozIStorageConnection *aDBConn) 1.36 +{ 1.37 + nsRefPtr<GenerateGUIDFunction> function = new GenerateGUIDFunction(); 1.38 + nsresult rv = aDBConn->CreateFunction( 1.39 + NS_LITERAL_CSTRING("generate_guid"), 0, function 1.40 + ); 1.41 + NS_ENSURE_SUCCESS(rv, rv); 1.42 + 1.43 + return NS_OK; 1.44 +} 1.45 + 1.46 +NS_IMPL_ISUPPORTS( 1.47 + GenerateGUIDFunction, 1.48 + mozIStorageFunction 1.49 +) 1.50 + 1.51 +static 1.52 +nsresult 1.53 +Base64urlEncode(const uint8_t* aBytes, 1.54 + uint32_t aNumBytes, 1.55 + nsCString& _result) 1.56 +{ 1.57 + // SetLength does not set aside space for null termination. PL_Base64Encode 1.58 + // will not null terminate, however, nsCStrings must be null terminated. As a 1.59 + // result, we set the capacity to be one greater than what we need, and the 1.60 + // length to our desired length. 1.61 + uint32_t length = (aNumBytes + 2) / 3 * 4; // +2 due to integer math. 1.62 + NS_ENSURE_TRUE(_result.SetCapacity(length + 1, mozilla::fallible_t()), 1.63 + NS_ERROR_OUT_OF_MEMORY); 1.64 + _result.SetLength(length); 1.65 + (void)PL_Base64Encode(reinterpret_cast<const char*>(aBytes), aNumBytes, 1.66 + _result.BeginWriting()); 1.67 + 1.68 + // base64url encoding is defined in RFC 4648. It replaces the last two 1.69 + // alphabet characters of base64 encoding with '-' and '_' respectively. 1.70 + _result.ReplaceChar('+', '-'); 1.71 + _result.ReplaceChar('/', '_'); 1.72 + return NS_OK; 1.73 +} 1.74 + 1.75 +#ifdef XP_WIN 1.76 +// Included here because windows.h conflicts with the use of mozIStorageError 1.77 +// above. 1.78 +#include <windows.h> 1.79 +#include <wincrypt.h> 1.80 +#endif 1.81 + 1.82 +static 1.83 +nsresult 1.84 +GenerateRandomBytes(uint32_t aSize, 1.85 + uint8_t* _buffer) 1.86 +{ 1.87 + // On Windows, we'll use its built-in cryptographic API. 1.88 +#if defined(XP_WIN) 1.89 + HCRYPTPROV cryptoProvider; 1.90 + BOOL rc = CryptAcquireContext(&cryptoProvider, 0, 0, PROV_RSA_FULL, 1.91 + CRYPT_VERIFYCONTEXT | CRYPT_SILENT); 1.92 + if (rc) { 1.93 + rc = CryptGenRandom(cryptoProvider, aSize, _buffer); 1.94 + (void)CryptReleaseContext(cryptoProvider, 0); 1.95 + } 1.96 + return rc ? NS_OK : NS_ERROR_FAILURE; 1.97 + 1.98 + // On Unix, we'll just read in from /dev/urandom. 1.99 +#elif defined(XP_UNIX) 1.100 + NS_ENSURE_ARG_MAX(aSize, INT32_MAX); 1.101 + PRFileDesc* urandom = PR_Open("/dev/urandom", PR_RDONLY, 0); 1.102 + nsresult rv = NS_ERROR_FAILURE; 1.103 + if (urandom) { 1.104 + int32_t bytesRead = PR_Read(urandom, _buffer, aSize); 1.105 + if (bytesRead == static_cast<int32_t>(aSize)) { 1.106 + rv = NS_OK; 1.107 + } 1.108 + (void)PR_Close(urandom); 1.109 + } 1.110 + return rv; 1.111 +#endif 1.112 +} 1.113 + 1.114 +nsresult 1.115 +GenerateGUID(nsCString& _guid) 1.116 +{ 1.117 + _guid.Truncate(); 1.118 + 1.119 + // Request raw random bytes and base64url encode them. For each set of three 1.120 + // bytes, we get one character. 1.121 + const uint32_t kRequiredBytesLength = 1.122 + static_cast<uint32_t>(GUID_LENGTH / 4 * 3); 1.123 + 1.124 + uint8_t buffer[kRequiredBytesLength]; 1.125 + nsresult rv = GenerateRandomBytes(kRequiredBytesLength, buffer); 1.126 + NS_ENSURE_SUCCESS(rv, rv); 1.127 + 1.128 + rv = Base64urlEncode(buffer, kRequiredBytesLength, _guid); 1.129 + NS_ENSURE_SUCCESS(rv, rv); 1.130 + 1.131 + NS_ASSERTION(_guid.Length() == GUID_LENGTH, "GUID is not the right size!"); 1.132 + return NS_OK; 1.133 +} 1.134 + 1.135 +////////////////////////////////////////////////////////////////////////////// 1.136 +//// mozIStorageFunction 1.137 + 1.138 +NS_IMETHODIMP 1.139 +GenerateGUIDFunction::OnFunctionCall(mozIStorageValueArray *aArguments, 1.140 + nsIVariant **_result) 1.141 +{ 1.142 + nsAutoCString guid; 1.143 + nsresult rv = GenerateGUID(guid); 1.144 + NS_ENSURE_SUCCESS(rv, rv); 1.145 + 1.146 + NS_ADDREF(*_result = new mozilla::storage::UTF8TextVariant(guid)); 1.147 + return NS_OK; 1.148 +} 1.149 + 1.150 +} // namespace mozilla 1.151 +} // namespace downloads