tor-browser

The Tor Browser
git clone https://git.dasho.dev/tor-browser.git
Log | Files | Refs | README | LICENSE

TestStorageConnection.cpp (9960B)


      1 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
      2 /* vim: set ts=8 sts=2 et sw=2 tw=80: */
      3 /* This Source Code Form is subject to the terms of the Mozilla Public
      4 * License, v. 2.0. If a copy of the MPL was not distributed with this file,
      5 * You can obtain one at http://mozilla.org/MPL/2.0/. */
      6 
      7 #include "QuotaManagerDependencyFixture.h"
      8 #include "mozIStorageConnection.h"
      9 #include "mozIStorageService.h"
     10 #include "mozStorageCID.h"
     11 #include "mozilla/dom/quota/IPCStreamCipherStrategy.h"
     12 #include "mozilla/dom/quota/QuotaCommon.h"
     13 #include "mozilla/dom/quota/QuotaManager.h"
     14 #include "mozilla/dom/quota/QuotaObject.h"
     15 #include "mozilla/dom/quota/ResultExtensions.h"
     16 #include "nsIFile.h"
     17 #include "nsIFileProtocolHandler.h"
     18 #include "nsIFileURL.h"
     19 #include "nsIURIMutator.h"
     20 #include "nss.h"
     21 
     22 namespace mozilla {
     23 
     24 struct NSSInitContextDeleter {
     25  void operator()(NSSInitContext* p) { NSS_ShutdownContext(p); }
     26 };
     27 
     28 namespace dom::quota::test {
     29 
     30 namespace {
     31 
     32 void InitializeClientDirectory(const ClientMetadata& aClientMetadata) {
     33  QuotaManager* quotaManager = QuotaManager::Get();
     34 
     35  QM_TRY_INSPECT(
     36      const auto& directory,
     37      quotaManager->GetOrCreateTemporaryOriginDirectory(aClientMetadata),
     38      QM_TEST_FAIL);
     39 
     40  QM_TRY(MOZ_TO_RESULT(directory->Append(
     41             Client::TypeToString(aClientMetadata.mClientType))),
     42         QM_TEST_FAIL);
     43 
     44  QM_TRY_INSPECT(const bool& exists,
     45                 MOZ_TO_RESULT_INVOKE_MEMBER(directory, Exists), QM_TEST_FAIL);
     46 
     47  if (!exists) {
     48    QM_TRY(MOZ_TO_RESULT(directory->Create(nsIFile::DIRECTORY_TYPE, 0755)),
     49           QM_TEST_FAIL);
     50  }
     51 }
     52 
     53 void CreateStorageConnection(
     54    const ClientMetadata& aClientMetadata,
     55    const Maybe<int64_t>& aMaybeDirectoryLockId,
     56    const Maybe<IPCStreamCipherStrategy::KeyType>& aMaybeKey,
     57    nsCOMPtr<mozIStorageConnection>& aConnection) {
     58  QuotaManager* quotaManager = QuotaManager::Get();
     59 
     60  QM_TRY_UNWRAP(auto databaseFile,
     61                quotaManager->GetOriginDirectory(aClientMetadata),
     62                QM_TEST_FAIL);
     63 
     64  QM_TRY(MOZ_TO_RESULT(databaseFile->Append(
     65             Client::TypeToString(aClientMetadata.mClientType))),
     66         QM_TEST_FAIL);
     67 
     68  QM_TRY(MOZ_TO_RESULT(databaseFile->Append(u"testdatabase.sqlite"_ns)),
     69         QM_TEST_FAIL);
     70 
     71  QM_TRY_INSPECT(
     72      const auto& protocolHandler,
     73      MOZ_TO_RESULT_GET_TYPED(nsCOMPtr<nsIProtocolHandler>,
     74                              MOZ_SELECT_OVERLOAD(do_GetService),
     75                              NS_NETWORK_PROTOCOL_CONTRACTID_PREFIX "file"),
     76      QM_TEST_FAIL);
     77 
     78  QM_TRY_INSPECT(const auto& fileHandler,
     79                 MOZ_TO_RESULT_GET_TYPED(nsCOMPtr<nsIFileProtocolHandler>,
     80                                         MOZ_SELECT_OVERLOAD(do_QueryInterface),
     81                                         protocolHandler),
     82                 QM_TEST_FAIL);
     83 
     84  QM_TRY_INSPECT(
     85      const auto& mutator,
     86      MOZ_TO_RESULT_INVOKE_MEMBER_TYPED(nsCOMPtr<nsIURIMutator>, fileHandler,
     87                                        NewFileURIMutator, databaseFile),
     88      QM_TEST_FAIL);
     89 
     90  const auto directoryLockIdClause = [&aMaybeDirectoryLockId] {
     91    nsAutoCString directoryLockIdClause;
     92    if (aMaybeDirectoryLockId) {
     93      directoryLockIdClause =
     94          "&directoryLockId="_ns + IntToCString(*aMaybeDirectoryLockId);
     95    }
     96    return directoryLockIdClause;
     97  }();
     98 
     99  const auto keyClause = [&aMaybeKey] {
    100    nsAutoCString keyClause;
    101    if (aMaybeKey) {
    102      keyClause.AssignLiteral("&key=");
    103      for (uint8_t byte : IPCStreamCipherStrategy::SerializeKey(*aMaybeKey)) {
    104        keyClause.AppendPrintf("%02x", byte);
    105      }
    106    }
    107    return keyClause;
    108  }();
    109 
    110  QM_TRY_INSPECT(
    111      const auto& fileURL,
    112      ([&mutator, &directoryLockIdClause,
    113        &keyClause]() -> Result<nsCOMPtr<nsIFileURL>, nsresult> {
    114        nsCOMPtr<nsIFileURL> result;
    115        QM_TRY(MOZ_TO_RESULT(NS_MutateURI(mutator)
    116                                 .SetQuery("cache=private"_ns +
    117                                           directoryLockIdClause + keyClause)
    118                                 .Finalize(result)));
    119        return result;
    120      }()),
    121      QM_TEST_FAIL);
    122 
    123  QM_TRY_INSPECT(const auto& storageService,
    124                 MOZ_TO_RESULT_GET_TYPED(nsCOMPtr<mozIStorageService>,
    125                                         MOZ_SELECT_OVERLOAD(do_GetService),
    126                                         MOZ_STORAGE_SERVICE_CONTRACTID),
    127                 QM_TEST_FAIL);
    128 
    129  QM_TRY_UNWRAP(auto connection,
    130                MOZ_TO_RESULT_INVOKE_MEMBER_TYPED(
    131                    nsCOMPtr<mozIStorageConnection>, storageService,
    132                    OpenDatabaseWithFileURL, fileURL, EmptyCString(),
    133                    mozIStorageService::CONNECTION_DEFAULT),
    134                QM_TEST_FAIL);
    135 
    136  QM_TRY(MOZ_TO_RESULT(
    137             connection->ExecuteSimpleSQL("PRAGMA journal_mode = wal;"_ns)),
    138         QM_TEST_FAIL);
    139 
    140  // The connection needs to be re-created, otherwise GetQuotaObjects is not
    141  // able to get the quota object for the journal file.
    142 
    143  QM_TRY(MOZ_TO_RESULT(connection->Close()), QM_TEST_FAIL);
    144 
    145  QM_TRY_UNWRAP(connection,
    146                MOZ_TO_RESULT_INVOKE_MEMBER_TYPED(
    147                    nsCOMPtr<mozIStorageConnection>, storageService,
    148                    OpenDatabaseWithFileURL, fileURL, EmptyCString(),
    149                    mozIStorageService::CONNECTION_DEFAULT),
    150                QM_TEST_FAIL);
    151 
    152  aConnection = std::move(connection);
    153 }
    154 
    155 }  // namespace
    156 
    157 class TestStorageConnection : public QuotaManagerDependencyFixture {
    158 public:
    159  static void SetUpTestCase() {
    160    // Do this only once, do not tear it down per test case.
    161    if (!sNssContext) {
    162      sNssContext.reset(
    163          NSS_InitContext("", "", "", "", nullptr,
    164                          NSS_INIT_READONLY | NSS_INIT_NOCERTDB |
    165                              NSS_INIT_NOMODDB | NSS_INIT_FORCEOPEN |
    166                              NSS_INIT_OPTIMIZESPACE | NSS_INIT_NOROOTINIT));
    167    }
    168 
    169    ASSERT_NO_FATAL_FAILURE(InitializeFixture());
    170  }
    171 
    172  static void TearDownTestCase() {
    173    ASSERT_NO_FATAL_FAILURE(ShutdownFixture());
    174 
    175    sNssContext = nullptr;
    176  }
    177 
    178  void TearDown() override {
    179    ASSERT_NO_FATAL_FAILURE(ClearStoragesForOrigin(GetTestOriginMetadata()));
    180  }
    181 
    182 private:
    183  struct NSSInitContextDeleter {
    184    void operator()(NSSInitContext* p) { NSS_ShutdownContext(p); }
    185  };
    186  static std::unique_ptr<NSSInitContext, NSSInitContextDeleter> sNssContext;
    187 };
    188 constinit std::unique_ptr<NSSInitContext,
    189                          TestStorageConnection::NSSInitContextDeleter>
    190    TestStorageConnection::sNssContext;
    191 
    192 TEST_F(TestStorageConnection, BaseVFS) {
    193  // XXX This call can't be wrapped with ASSERT_NO_FATAL_FAILURE because
    194  // base-toolchains builds fail with: error: duplicate label
    195  // 'gtest_label_testnofatal_214'
    196  PerformClientDirectoryTest(GetTestClientMetadata(), [](int64_t) {
    197    ASSERT_NO_FATAL_FAILURE(InitializeClientDirectory(GetTestClientMetadata()));
    198 
    199    nsCOMPtr<mozIStorageConnection> connection;
    200    ASSERT_NO_FATAL_FAILURE(CreateStorageConnection(
    201        GetTestClientMetadata(), Nothing(), Nothing(), connection));
    202 
    203    RefPtr<QuotaObject> quotaObject;
    204    RefPtr<QuotaObject> journalQuotaObject;
    205 
    206    nsresult rv = connection->GetQuotaObjects(
    207        getter_AddRefs(quotaObject), getter_AddRefs(journalQuotaObject));
    208    ASSERT_EQ(rv, NS_ERROR_FAILURE);
    209 
    210    ASSERT_FALSE(quotaObject);
    211    ASSERT_FALSE(journalQuotaObject);
    212 
    213    QM_TRY(MOZ_TO_RESULT(connection->Close()), QM_TEST_FAIL);
    214  });
    215 }
    216 
    217 TEST_F(TestStorageConnection, QuotaVFS) {
    218  // XXX This call can't be wrapped with ASSERT_NO_FATAL_FAILURE because
    219  // base-toolchains builds fail with: error: duplicate label
    220  // 'gtest_label_testnofatal_214'
    221  PerformClientDirectoryTest(
    222      GetTestClientMetadata(), [](int64_t aDirectoryLockId) {
    223        ASSERT_NO_FATAL_FAILURE(
    224            InitializeClientDirectory(GetTestClientMetadata()));
    225 
    226        nsCOMPtr<mozIStorageConnection> connection;
    227        ASSERT_NO_FATAL_FAILURE(CreateStorageConnection(GetTestClientMetadata(),
    228                                                        Some(aDirectoryLockId),
    229                                                        Nothing(), connection));
    230 
    231        RefPtr<QuotaObject> quotaObject;
    232        RefPtr<QuotaObject> journalQuotaObject;
    233 
    234        QM_TRY(MOZ_TO_RESULT(connection->GetQuotaObjects(
    235                   getter_AddRefs(quotaObject),
    236                   getter_AddRefs(journalQuotaObject))),
    237               QM_TEST_FAIL);
    238 
    239        ASSERT_TRUE(quotaObject);
    240        ASSERT_TRUE(journalQuotaObject);
    241 
    242        QM_TRY(MOZ_TO_RESULT(connection->Close()), QM_TEST_FAIL);
    243      });
    244 }
    245 
    246 TEST_F(TestStorageConnection, ObfuscatingVFS) {
    247  // XXX This call can't be wrapped with ASSERT_NO_FATAL_FAILURE because
    248  // base-toolchains builds fail with: error: duplicate label
    249  // 'gtest_label_testnofatal_214'
    250  PerformClientDirectoryTest(
    251      GetTestClientMetadata(), [](int64_t aDirectoryLockId) {
    252        ASSERT_NO_FATAL_FAILURE(
    253            InitializeClientDirectory(GetTestClientMetadata()));
    254 
    255        QM_TRY_INSPECT(const auto& key, IPCStreamCipherStrategy::GenerateKey(),
    256                       QM_TEST_FAIL);
    257 
    258        nsCOMPtr<mozIStorageConnection> connection;
    259        ASSERT_NO_FATAL_FAILURE(CreateStorageConnection(GetTestClientMetadata(),
    260                                                        Some(aDirectoryLockId),
    261                                                        Some(key), connection));
    262 
    263        RefPtr<QuotaObject> quotaObject;
    264        RefPtr<QuotaObject> journalQuotaObject;
    265 
    266        QM_TRY(MOZ_TO_RESULT(connection->GetQuotaObjects(
    267                   getter_AddRefs(quotaObject),
    268                   getter_AddRefs(journalQuotaObject))),
    269               QM_TEST_FAIL);
    270 
    271        ASSERT_TRUE(quotaObject);
    272        ASSERT_TRUE(journalQuotaObject);
    273 
    274        QM_TRY(MOZ_TO_RESULT(connection->Close()), QM_TEST_FAIL);
    275      });
    276 }
    277 
    278 }  // namespace dom::quota::test
    279 }  // namespace mozilla