toolkit/components/downloads/SQLFunctions.cpp

branch
TOR_BUG_9701
changeset 14
925c144e1f1f
equal deleted inserted replaced
-1:000000000000 0:e670619663d2
1 /* vim: sw=2 ts=2 et lcs=trail\:.,tab\:>~ :
2 * This Source Code Form is subject to the terms of the Mozilla Public
3 * License, v. 2.0. If a copy of the MPL was not distributed with this
4 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
5
6 #include "mozilla/storage.h"
7 #include "mozilla/storage/Variant.h"
8 #include "mozilla/mozalloc.h"
9 #include "nsString.h"
10 #include "SQLFunctions.h"
11 #include "nsUTF8Utils.h"
12 #include "plbase64.h"
13 #include "prio.h"
14
15 // The length of guids that are used by the download manager
16 #define GUID_LENGTH 12
17
18 namespace mozilla {
19 namespace downloads {
20
21 // Keep this file in sync with the GUID-related code in toolkit/places/SQLFunctions.cpp
22 // and toolkit/places/Helpers.cpp!
23
24 ////////////////////////////////////////////////////////////////////////////////
25 //// GUID Creation Function
26
27 //////////////////////////////////////////////////////////////////////////////
28 //// GenerateGUIDFunction
29
30 /* static */
31 nsresult
32 GenerateGUIDFunction::create(mozIStorageConnection *aDBConn)
33 {
34 nsRefPtr<GenerateGUIDFunction> function = new GenerateGUIDFunction();
35 nsresult rv = aDBConn->CreateFunction(
36 NS_LITERAL_CSTRING("generate_guid"), 0, function
37 );
38 NS_ENSURE_SUCCESS(rv, rv);
39
40 return NS_OK;
41 }
42
43 NS_IMPL_ISUPPORTS(
44 GenerateGUIDFunction,
45 mozIStorageFunction
46 )
47
48 static
49 nsresult
50 Base64urlEncode(const uint8_t* aBytes,
51 uint32_t aNumBytes,
52 nsCString& _result)
53 {
54 // SetLength does not set aside space for null termination. PL_Base64Encode
55 // will not null terminate, however, nsCStrings must be null terminated. As a
56 // result, we set the capacity to be one greater than what we need, and the
57 // length to our desired length.
58 uint32_t length = (aNumBytes + 2) / 3 * 4; // +2 due to integer math.
59 NS_ENSURE_TRUE(_result.SetCapacity(length + 1, mozilla::fallible_t()),
60 NS_ERROR_OUT_OF_MEMORY);
61 _result.SetLength(length);
62 (void)PL_Base64Encode(reinterpret_cast<const char*>(aBytes), aNumBytes,
63 _result.BeginWriting());
64
65 // base64url encoding is defined in RFC 4648. It replaces the last two
66 // alphabet characters of base64 encoding with '-' and '_' respectively.
67 _result.ReplaceChar('+', '-');
68 _result.ReplaceChar('/', '_');
69 return NS_OK;
70 }
71
72 #ifdef XP_WIN
73 // Included here because windows.h conflicts with the use of mozIStorageError
74 // above.
75 #include <windows.h>
76 #include <wincrypt.h>
77 #endif
78
79 static
80 nsresult
81 GenerateRandomBytes(uint32_t aSize,
82 uint8_t* _buffer)
83 {
84 // On Windows, we'll use its built-in cryptographic API.
85 #if defined(XP_WIN)
86 HCRYPTPROV cryptoProvider;
87 BOOL rc = CryptAcquireContext(&cryptoProvider, 0, 0, PROV_RSA_FULL,
88 CRYPT_VERIFYCONTEXT | CRYPT_SILENT);
89 if (rc) {
90 rc = CryptGenRandom(cryptoProvider, aSize, _buffer);
91 (void)CryptReleaseContext(cryptoProvider, 0);
92 }
93 return rc ? NS_OK : NS_ERROR_FAILURE;
94
95 // On Unix, we'll just read in from /dev/urandom.
96 #elif defined(XP_UNIX)
97 NS_ENSURE_ARG_MAX(aSize, INT32_MAX);
98 PRFileDesc* urandom = PR_Open("/dev/urandom", PR_RDONLY, 0);
99 nsresult rv = NS_ERROR_FAILURE;
100 if (urandom) {
101 int32_t bytesRead = PR_Read(urandom, _buffer, aSize);
102 if (bytesRead == static_cast<int32_t>(aSize)) {
103 rv = NS_OK;
104 }
105 (void)PR_Close(urandom);
106 }
107 return rv;
108 #endif
109 }
110
111 nsresult
112 GenerateGUID(nsCString& _guid)
113 {
114 _guid.Truncate();
115
116 // Request raw random bytes and base64url encode them. For each set of three
117 // bytes, we get one character.
118 const uint32_t kRequiredBytesLength =
119 static_cast<uint32_t>(GUID_LENGTH / 4 * 3);
120
121 uint8_t buffer[kRequiredBytesLength];
122 nsresult rv = GenerateRandomBytes(kRequiredBytesLength, buffer);
123 NS_ENSURE_SUCCESS(rv, rv);
124
125 rv = Base64urlEncode(buffer, kRequiredBytesLength, _guid);
126 NS_ENSURE_SUCCESS(rv, rv);
127
128 NS_ASSERTION(_guid.Length() == GUID_LENGTH, "GUID is not the right size!");
129 return NS_OK;
130 }
131
132 //////////////////////////////////////////////////////////////////////////////
133 //// mozIStorageFunction
134
135 NS_IMETHODIMP
136 GenerateGUIDFunction::OnFunctionCall(mozIStorageValueArray *aArguments,
137 nsIVariant **_result)
138 {
139 nsAutoCString guid;
140 nsresult rv = GenerateGUID(guid);
141 NS_ENSURE_SUCCESS(rv, rv);
142
143 NS_ADDREF(*_result = new mozilla::storage::UTF8TextVariant(guid));
144 return NS_OK;
145 }
146
147 } // namespace mozilla
148 } // namespace downloads

mercurial