SQLFunctions.cpp 4.2 KB

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