forked from mirrors/gecko-dev
Bug 1835298: Encrypt CacheAPI data on disk in PBM.r=dom-storage-reviewers,janv
Depends on D180296 Differential Revision: https://phabricator.services.mozilla.com/D180297
This commit is contained in:
parent
0890b51845
commit
a68c2ad072
19 changed files with 428 additions and 187 deletions
3
dom/cache/Action.h
vendored
3
dom/cache/Action.h
vendored
|
|
@ -7,6 +7,7 @@
|
||||||
#ifndef mozilla_dom_cache_Action_h
|
#ifndef mozilla_dom_cache_Action_h
|
||||||
#define mozilla_dom_cache_Action_h
|
#define mozilla_dom_cache_Action_h
|
||||||
|
|
||||||
|
#include "CacheCipherKeyManager.h"
|
||||||
#include "mozilla/Atomics.h"
|
#include "mozilla/Atomics.h"
|
||||||
#include "mozilla/dom/cache/Types.h"
|
#include "mozilla/dom/cache/Types.h"
|
||||||
#include "mozilla/dom/SafeRefPtr.h"
|
#include "mozilla/dom/SafeRefPtr.h"
|
||||||
|
|
@ -56,7 +57,7 @@ class Action : public SafeRefCounted<Action> {
|
||||||
virtual void RunOnTarget(
|
virtual void RunOnTarget(
|
||||||
SafeRefPtr<Resolver> aResolver,
|
SafeRefPtr<Resolver> aResolver,
|
||||||
const Maybe<CacheDirectoryMetadata>& aDirectoryMetadata,
|
const Maybe<CacheDirectoryMetadata>& aDirectoryMetadata,
|
||||||
Data* aOptionalData) = 0;
|
Data* aOptionalData, const Maybe<CipherKey>& aMaybeCipherKey) = 0;
|
||||||
|
|
||||||
// Called on initiating thread when the Action is canceled. The Action is
|
// Called on initiating thread when the Action is canceled. The Action is
|
||||||
// responsible for calling Resolver::Resolve() as normal; either with a
|
// responsible for calling Resolver::Resolve() as normal; either with a
|
||||||
|
|
|
||||||
21
dom/cache/CacheCipherKeyManager.h
vendored
Normal file
21
dom/cache/CacheCipherKeyManager.h
vendored
Normal file
|
|
@ -0,0 +1,21 @@
|
||||||
|
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
||||||
|
/* vim: set ts=8 sts=2 et sw=2 tw=80: */
|
||||||
|
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||||
|
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||||
|
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||||
|
|
||||||
|
#ifndef DOM_CACHE_CACHECIPHERKEYMANAGER_H_
|
||||||
|
#define DOM_CACHE_CACHECIPHERKEYMANAGER_H_
|
||||||
|
|
||||||
|
#include "mozilla/dom/quota/CipherKeyManager.h"
|
||||||
|
#include "mozilla/dom/quota/IPCStreamCipherStrategy.h"
|
||||||
|
|
||||||
|
namespace mozilla::dom::cache {
|
||||||
|
|
||||||
|
using CipherStrategy = mozilla::dom::quota::IPCStreamCipherStrategy;
|
||||||
|
using CipherKeyManager = mozilla::dom::quota::CipherKeyManager<CipherStrategy>;
|
||||||
|
using CipherKey = CipherStrategy::KeyType;
|
||||||
|
|
||||||
|
} // namespace mozilla::dom::cache
|
||||||
|
|
||||||
|
#endif // DOM_CACHE_CACHECIPHERKEYMANAGER_H_
|
||||||
73
dom/cache/Context.cpp
vendored
73
dom/cache/Context.cpp
vendored
|
|
@ -5,7 +5,6 @@
|
||||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||||
|
|
||||||
#include "mozilla/dom/cache/Context.h"
|
#include "mozilla/dom/cache/Context.h"
|
||||||
|
|
||||||
#include "CacheCommon.h"
|
#include "CacheCommon.h"
|
||||||
|
|
||||||
#include "mozilla/AutoRestore.h"
|
#include "mozilla/AutoRestore.h"
|
||||||
|
|
@ -19,11 +18,13 @@
|
||||||
#include "mozilla/dom/quota/QuotaManager.h"
|
#include "mozilla/dom/quota/QuotaManager.h"
|
||||||
#include "mozilla/dom/quota/ResultExtensions.h"
|
#include "mozilla/dom/quota/ResultExtensions.h"
|
||||||
#include "mozilla/ipc/PBackgroundSharedTypes.h"
|
#include "mozilla/ipc/PBackgroundSharedTypes.h"
|
||||||
|
#include "mozilla/Maybe.h"
|
||||||
#include "mozIStorageConnection.h"
|
#include "mozIStorageConnection.h"
|
||||||
#include "nsIPrincipal.h"
|
#include "nsIPrincipal.h"
|
||||||
#include "nsIRunnable.h"
|
#include "nsIRunnable.h"
|
||||||
#include "nsIThread.h"
|
#include "nsIThread.h"
|
||||||
#include "nsThreadUtils.h"
|
#include "nsThreadUtils.h"
|
||||||
|
#include "QuotaClientImpl.h"
|
||||||
|
|
||||||
namespace {
|
namespace {
|
||||||
|
|
||||||
|
|
@ -35,8 +36,9 @@ class NullAction final : public Action {
|
||||||
NullAction() = default;
|
NullAction() = default;
|
||||||
|
|
||||||
virtual void RunOnTarget(mozilla::SafeRefPtr<Resolver> aResolver,
|
virtual void RunOnTarget(mozilla::SafeRefPtr<Resolver> aResolver,
|
||||||
const mozilla::Maybe<CacheDirectoryMetadata>&,
|
const mozilla::Maybe<CacheDirectoryMetadata>&, Data*,
|
||||||
Data*) override {
|
const mozilla::Maybe<mozilla::dom::cache::CipherKey>&
|
||||||
|
/* aMaybeCipherKey */) override {
|
||||||
// Resolve success immediately. This Action does no actual work.
|
// Resolve success immediately. This Action does no actual work.
|
||||||
MOZ_DIAGNOSTIC_ASSERT(aResolver);
|
MOZ_DIAGNOSTIC_ASSERT(aResolver);
|
||||||
aResolver->Resolve(NS_OK);
|
aResolver->Resolve(NS_OK);
|
||||||
|
|
@ -216,6 +218,7 @@ class Context::QuotaInitRunnable final : public nsIRunnable {
|
||||||
Maybe<mozilla::ipc::PrincipalInfo> mPrincipalInfo;
|
Maybe<mozilla::ipc::PrincipalInfo> mPrincipalInfo;
|
||||||
Maybe<CacheDirectoryMetadata> mDirectoryMetadata;
|
Maybe<CacheDirectoryMetadata> mDirectoryMetadata;
|
||||||
RefPtr<DirectoryLock> mDirectoryLock;
|
RefPtr<DirectoryLock> mDirectoryLock;
|
||||||
|
RefPtr<CipherKeyManager> mCipherKeyManager;
|
||||||
State mState;
|
State mState;
|
||||||
Atomic<bool> mCanceled;
|
Atomic<bool> mCanceled;
|
||||||
|
|
||||||
|
|
@ -399,11 +402,18 @@ Context::QuotaInitRunnable::Run() {
|
||||||
QM_TRY(
|
QM_TRY(
|
||||||
MOZ_TO_RESULT(quotaManager->EnsureTemporaryStorageIsInitialized()));
|
MOZ_TO_RESULT(quotaManager->EnsureTemporaryStorageIsInitialized()));
|
||||||
|
|
||||||
QM_TRY_UNWRAP(mDirectoryMetadata->mDir,
|
QM_TRY_UNWRAP(
|
||||||
quotaManager
|
mDirectoryMetadata->mDir,
|
||||||
->EnsureTemporaryOriginIsInitialized(
|
quotaManager
|
||||||
PERSISTENCE_TYPE_DEFAULT, *mDirectoryMetadata)
|
->EnsureTemporaryOriginIsInitialized(
|
||||||
.map([](const auto& res) { return res.first; }));
|
mDirectoryMetadata->mPersistenceType, *mDirectoryMetadata)
|
||||||
|
.map([](const auto& res) { return res.first; }));
|
||||||
|
|
||||||
|
auto* cacheQuotaClient = CacheQuotaClient::Get();
|
||||||
|
MOZ_DIAGNOSTIC_ASSERT(cacheQuotaClient);
|
||||||
|
|
||||||
|
mCipherKeyManager =
|
||||||
|
cacheQuotaClient->GetOrCreateCipherKeyManager(*mDirectoryMetadata);
|
||||||
|
|
||||||
mState = STATE_RUN_ON_TARGET;
|
mState = STATE_RUN_ON_TARGET;
|
||||||
|
|
||||||
|
|
@ -427,7 +437,11 @@ Context::QuotaInitRunnable::Run() {
|
||||||
|
|
||||||
// Execute the provided initialization Action. The Action must Resolve()
|
// Execute the provided initialization Action. The Action must Resolve()
|
||||||
// before returning.
|
// before returning.
|
||||||
mInitAction->RunOnTarget(resolver.clonePtr(), mDirectoryMetadata, mData);
|
|
||||||
|
mInitAction->RunOnTarget(
|
||||||
|
resolver.clonePtr(), mDirectoryMetadata, mData,
|
||||||
|
mCipherKeyManager ? Some(mCipherKeyManager->Ensure()) : Nothing{});
|
||||||
|
|
||||||
MOZ_DIAGNOSTIC_ASSERT(resolver->Resolved());
|
MOZ_DIAGNOSTIC_ASSERT(resolver->Resolved());
|
||||||
|
|
||||||
mData = nullptr;
|
mData = nullptr;
|
||||||
|
|
@ -445,8 +459,11 @@ Context::QuotaInitRunnable::Run() {
|
||||||
case STATE_COMPLETING: {
|
case STATE_COMPLETING: {
|
||||||
NS_ASSERT_OWNINGTHREAD(QuotaInitRunnable);
|
NS_ASSERT_OWNINGTHREAD(QuotaInitRunnable);
|
||||||
mInitAction->CompleteOnInitiatingThread(mResult);
|
mInitAction->CompleteOnInitiatingThread(mResult);
|
||||||
|
|
||||||
mContext->OnQuotaInit(mResult, mDirectoryMetadata,
|
mContext->OnQuotaInit(mResult, mDirectoryMetadata,
|
||||||
mDirectoryLock.forget());
|
mDirectoryLock.forget(),
|
||||||
|
mCipherKeyManager.forget());
|
||||||
|
|
||||||
mState = STATE_COMPLETE;
|
mState = STATE_COMPLETE;
|
||||||
|
|
||||||
// Explicitly cleanup here as the destructor could fire on any of
|
// Explicitly cleanup here as the destructor could fire on any of
|
||||||
|
|
@ -477,12 +494,14 @@ class Context::ActionRunnable final : public nsIRunnable,
|
||||||
public:
|
public:
|
||||||
ActionRunnable(SafeRefPtr<Context> aContext, Data* aData,
|
ActionRunnable(SafeRefPtr<Context> aContext, Data* aData,
|
||||||
nsISerialEventTarget* aTarget, SafeRefPtr<Action> aAction,
|
nsISerialEventTarget* aTarget, SafeRefPtr<Action> aAction,
|
||||||
const Maybe<CacheDirectoryMetadata>& aDirectoryMetadata)
|
const Maybe<CacheDirectoryMetadata>& aDirectoryMetadata,
|
||||||
|
RefPtr<CipherKeyManager> aCipherKeyManager)
|
||||||
: mContext(std::move(aContext)),
|
: mContext(std::move(aContext)),
|
||||||
mData(aData),
|
mData(aData),
|
||||||
mTarget(aTarget),
|
mTarget(aTarget),
|
||||||
mAction(std::move(aAction)),
|
mAction(std::move(aAction)),
|
||||||
mDirectoryMetadata(aDirectoryMetadata),
|
mDirectoryMetadata(aDirectoryMetadata),
|
||||||
|
mCipherKeyManager(std::move(aCipherKeyManager)),
|
||||||
mInitiatingThread(GetCurrentSerialEventTarget()),
|
mInitiatingThread(GetCurrentSerialEventTarget()),
|
||||||
mState(STATE_INIT),
|
mState(STATE_INIT),
|
||||||
mResult(NS_OK),
|
mResult(NS_OK),
|
||||||
|
|
@ -572,6 +591,7 @@ class Context::ActionRunnable final : public nsIRunnable,
|
||||||
nsCOMPtr<nsISerialEventTarget> mTarget;
|
nsCOMPtr<nsISerialEventTarget> mTarget;
|
||||||
SafeRefPtr<Action> mAction;
|
SafeRefPtr<Action> mAction;
|
||||||
const Maybe<CacheDirectoryMetadata> mDirectoryMetadata;
|
const Maybe<CacheDirectoryMetadata> mDirectoryMetadata;
|
||||||
|
RefPtr<CipherKeyManager> mCipherKeyManager;
|
||||||
nsCOMPtr<nsIEventTarget> mInitiatingThread;
|
nsCOMPtr<nsIEventTarget> mInitiatingThread;
|
||||||
State mState;
|
State mState;
|
||||||
nsresult mResult;
|
nsresult mResult;
|
||||||
|
|
@ -633,7 +653,9 @@ Context::ActionRunnable::Run() {
|
||||||
mExecutingRunOnTarget = true;
|
mExecutingRunOnTarget = true;
|
||||||
|
|
||||||
mState = STATE_RUNNING;
|
mState = STATE_RUNNING;
|
||||||
mAction->RunOnTarget(SafeRefPtrFromThis(), mDirectoryMetadata, mData);
|
mAction->RunOnTarget(
|
||||||
|
SafeRefPtrFromThis(), mDirectoryMetadata, mData,
|
||||||
|
mCipherKeyManager ? Some(mCipherKeyManager->Ensure()) : Nothing{});
|
||||||
|
|
||||||
mData = nullptr;
|
mData = nullptr;
|
||||||
|
|
||||||
|
|
@ -835,6 +857,19 @@ Maybe<DirectoryLock&> Context::MaybeDirectoryLockRef() const {
|
||||||
return ToMaybeRef(mDirectoryLock.get());
|
return ToMaybeRef(mDirectoryLock.get());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
CipherKeyManager& Context::MutableCipherKeyManagerRef() {
|
||||||
|
MOZ_ASSERT(mTarget->IsOnCurrentThread());
|
||||||
|
MOZ_DIAGNOSTIC_ASSERT(mCipherKeyManager);
|
||||||
|
|
||||||
|
return *mCipherKeyManager;
|
||||||
|
}
|
||||||
|
|
||||||
|
const Maybe<CacheDirectoryMetadata>& Context::MaybeCacheDirectoryMetadataRef()
|
||||||
|
const {
|
||||||
|
MOZ_ASSERT(mTarget->IsOnCurrentThread());
|
||||||
|
return mDirectoryMetadata;
|
||||||
|
}
|
||||||
|
|
||||||
void Context::CancelAll() {
|
void Context::CancelAll() {
|
||||||
NS_ASSERT_OWNINGTHREAD(Context);
|
NS_ASSERT_OWNINGTHREAD(Context);
|
||||||
|
|
||||||
|
|
@ -961,9 +996,9 @@ void Context::Start() {
|
||||||
void Context::DispatchAction(SafeRefPtr<Action> aAction, bool aDoomData) {
|
void Context::DispatchAction(SafeRefPtr<Action> aAction, bool aDoomData) {
|
||||||
NS_ASSERT_OWNINGTHREAD(Context);
|
NS_ASSERT_OWNINGTHREAD(Context);
|
||||||
|
|
||||||
auto runnable =
|
auto runnable = MakeSafeRefPtr<ActionRunnable>(
|
||||||
MakeSafeRefPtr<ActionRunnable>(SafeRefPtrFromThis(), mData, mTarget,
|
SafeRefPtrFromThis(), mData, mTarget, std::move(aAction),
|
||||||
std::move(aAction), mDirectoryMetadata);
|
mDirectoryMetadata, mCipherKeyManager);
|
||||||
|
|
||||||
if (aDoomData) {
|
if (aDoomData) {
|
||||||
mData = nullptr;
|
mData = nullptr;
|
||||||
|
|
@ -980,7 +1015,8 @@ void Context::DispatchAction(SafeRefPtr<Action> aAction, bool aDoomData) {
|
||||||
|
|
||||||
void Context::OnQuotaInit(
|
void Context::OnQuotaInit(
|
||||||
nsresult aRv, const Maybe<CacheDirectoryMetadata>& aDirectoryMetadata,
|
nsresult aRv, const Maybe<CacheDirectoryMetadata>& aDirectoryMetadata,
|
||||||
already_AddRefed<DirectoryLock> aDirectoryLock) {
|
already_AddRefed<DirectoryLock> aDirectoryLock,
|
||||||
|
already_AddRefed<CipherKeyManager> aCipherKeyManager) {
|
||||||
NS_ASSERT_OWNINGTHREAD(Context);
|
NS_ASSERT_OWNINGTHREAD(Context);
|
||||||
|
|
||||||
MOZ_DIAGNOSTIC_ASSERT(mInitRunnable);
|
MOZ_DIAGNOSTIC_ASSERT(mInitRunnable);
|
||||||
|
|
@ -988,6 +1024,11 @@ void Context::OnQuotaInit(
|
||||||
|
|
||||||
if (aDirectoryMetadata) {
|
if (aDirectoryMetadata) {
|
||||||
mDirectoryMetadata.emplace(*aDirectoryMetadata);
|
mDirectoryMetadata.emplace(*aDirectoryMetadata);
|
||||||
|
|
||||||
|
MOZ_DIAGNOSTIC_ASSERT(!mCipherKeyManager);
|
||||||
|
mCipherKeyManager = aCipherKeyManager;
|
||||||
|
|
||||||
|
MOZ_DIAGNOSTIC_ASSERT_IF(mDirectoryMetadata->mIsPrivate, mCipherKeyManager);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Always save the directory lock to ensure QuotaManager does not shutdown
|
// Always save the directory lock to ensure QuotaManager does not shutdown
|
||||||
|
|
|
||||||
9
dom/cache/Context.h
vendored
9
dom/cache/Context.h
vendored
|
|
@ -7,6 +7,7 @@
|
||||||
#ifndef mozilla_dom_cache_Context_h
|
#ifndef mozilla_dom_cache_Context_h
|
||||||
#define mozilla_dom_cache_Context_h
|
#define mozilla_dom_cache_Context_h
|
||||||
|
|
||||||
|
#include "CacheCipherKeyManager.h"
|
||||||
#include "mozilla/dom/SafeRefPtr.h"
|
#include "mozilla/dom/SafeRefPtr.h"
|
||||||
#include "mozilla/dom/cache/Types.h"
|
#include "mozilla/dom/cache/Types.h"
|
||||||
#include "nsCOMPtr.h"
|
#include "nsCOMPtr.h"
|
||||||
|
|
@ -125,6 +126,10 @@ class Context final : public SafeRefCounted<Context> {
|
||||||
|
|
||||||
Maybe<DirectoryLock&> MaybeDirectoryLockRef() const;
|
Maybe<DirectoryLock&> MaybeDirectoryLockRef() const;
|
||||||
|
|
||||||
|
CipherKeyManager& MutableCipherKeyManagerRef();
|
||||||
|
|
||||||
|
const Maybe<CacheDirectoryMetadata>& MaybeCacheDirectoryMetadataRef() const;
|
||||||
|
|
||||||
// Cancel any Actions running or waiting to run. This should allow the
|
// Cancel any Actions running or waiting to run. This should allow the
|
||||||
// Context to be released and Listener::RemoveContext() will be called
|
// Context to be released and Listener::RemoveContext() will be called
|
||||||
// when complete.
|
// when complete.
|
||||||
|
|
@ -178,7 +183,8 @@ class Context final : public SafeRefCounted<Context> {
|
||||||
void DispatchAction(SafeRefPtr<Action> aAction, bool aDoomData = false);
|
void DispatchAction(SafeRefPtr<Action> aAction, bool aDoomData = false);
|
||||||
void OnQuotaInit(nsresult aRv,
|
void OnQuotaInit(nsresult aRv,
|
||||||
const Maybe<CacheDirectoryMetadata>& aDirectoryMetadata,
|
const Maybe<CacheDirectoryMetadata>& aDirectoryMetadata,
|
||||||
already_AddRefed<DirectoryLock> aDirectoryLock);
|
already_AddRefed<DirectoryLock> aDirectoryLock,
|
||||||
|
already_AddRefed<CipherKeyManager> aCipherKeyManager);
|
||||||
|
|
||||||
SafeRefPtr<ThreadsafeHandle> CreateThreadsafeHandle();
|
SafeRefPtr<ThreadsafeHandle> CreateThreadsafeHandle();
|
||||||
|
|
||||||
|
|
@ -206,6 +212,7 @@ class Context final : public SafeRefCounted<Context> {
|
||||||
SafeRefPtr<ThreadsafeHandle> mThreadsafeHandle;
|
SafeRefPtr<ThreadsafeHandle> mThreadsafeHandle;
|
||||||
|
|
||||||
RefPtr<DirectoryLock> mDirectoryLock;
|
RefPtr<DirectoryLock> mDirectoryLock;
|
||||||
|
RefPtr<CipherKeyManager> mCipherKeyManager;
|
||||||
SafeRefPtr<Context> mNextContext;
|
SafeRefPtr<Context> mNextContext;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
|
|
|
||||||
41
dom/cache/DBAction.cpp
vendored
41
dom/cache/DBAction.cpp
vendored
|
|
@ -6,11 +6,11 @@
|
||||||
|
|
||||||
#include "mozilla/dom/cache/DBAction.h"
|
#include "mozilla/dom/cache/DBAction.h"
|
||||||
|
|
||||||
|
#include "mozilla/Assertions.h"
|
||||||
#include "mozilla/dom/cache/Connection.h"
|
#include "mozilla/dom/cache/Connection.h"
|
||||||
#include "mozilla/dom/cache/DBSchema.h"
|
#include "mozilla/dom/cache/DBSchema.h"
|
||||||
#include "mozilla/dom/cache/FileUtils.h"
|
#include "mozilla/dom/cache/FileUtils.h"
|
||||||
#include "mozilla/dom/cache/QuotaClient.h"
|
#include "mozilla/dom/cache/QuotaClient.h"
|
||||||
#include "mozilla/dom/quota/Assertions.h"
|
|
||||||
#include "mozilla/dom/quota/PersistenceType.h"
|
#include "mozilla/dom/quota/PersistenceType.h"
|
||||||
#include "mozilla/dom/quota/ResultExtensions.h"
|
#include "mozilla/dom/quota/ResultExtensions.h"
|
||||||
#include "mozilla/net/nsFileProtocolHandler.h"
|
#include "mozilla/net/nsFileProtocolHandler.h"
|
||||||
|
|
@ -21,16 +21,11 @@
|
||||||
#include "nsIURI.h"
|
#include "nsIURI.h"
|
||||||
#include "nsIURIMutator.h"
|
#include "nsIURIMutator.h"
|
||||||
#include "nsIFileURL.h"
|
#include "nsIFileURL.h"
|
||||||
#include "nsThreadUtils.h"
|
|
||||||
|
|
||||||
namespace mozilla::dom::cache {
|
namespace mozilla::dom::cache {
|
||||||
|
|
||||||
using mozilla::dom::quota::AssertIsOnIOThread;
|
|
||||||
using mozilla::dom::quota::Client;
|
|
||||||
using mozilla::dom::quota::CloneFileAndAppend;
|
using mozilla::dom::quota::CloneFileAndAppend;
|
||||||
using mozilla::dom::quota::IsDatabaseCorruptionError;
|
using mozilla::dom::quota::IsDatabaseCorruptionError;
|
||||||
using mozilla::dom::quota::PERSISTENCE_TYPE_DEFAULT;
|
|
||||||
using mozilla::dom::quota::PersistenceType;
|
|
||||||
|
|
||||||
namespace {
|
namespace {
|
||||||
|
|
||||||
|
|
@ -61,7 +56,7 @@ DBAction::~DBAction() = default;
|
||||||
void DBAction::RunOnTarget(
|
void DBAction::RunOnTarget(
|
||||||
SafeRefPtr<Resolver> aResolver,
|
SafeRefPtr<Resolver> aResolver,
|
||||||
const Maybe<CacheDirectoryMetadata>& aDirectoryMetadata,
|
const Maybe<CacheDirectoryMetadata>& aDirectoryMetadata,
|
||||||
Data* aOptionalData) {
|
Data* aOptionalData, const Maybe<CipherKey>& aMaybeCipherKey) {
|
||||||
MOZ_ASSERT(!NS_IsMainThread());
|
MOZ_ASSERT(!NS_IsMainThread());
|
||||||
MOZ_DIAGNOSTIC_ASSERT(aResolver);
|
MOZ_DIAGNOSTIC_ASSERT(aResolver);
|
||||||
MOZ_DIAGNOSTIC_ASSERT(aDirectoryMetadata);
|
MOZ_DIAGNOSTIC_ASSERT(aDirectoryMetadata);
|
||||||
|
|
@ -89,8 +84,9 @@ void DBAction::RunOnTarget(
|
||||||
|
|
||||||
// If there is no previous Action, then we must open one.
|
// If there is no previous Action, then we must open one.
|
||||||
if (!conn) {
|
if (!conn) {
|
||||||
QM_TRY_UNWRAP(conn, OpenConnection(*aDirectoryMetadata, *dbDir), QM_VOID,
|
QM_TRY_UNWRAP(conn,
|
||||||
resolveErr);
|
OpenConnection(*aDirectoryMetadata, *dbDir, aMaybeCipherKey),
|
||||||
|
QM_VOID, resolveErr);
|
||||||
MOZ_DIAGNOSTIC_ASSERT(conn);
|
MOZ_DIAGNOSTIC_ASSERT(conn);
|
||||||
|
|
||||||
// Save this connection in the shared Data object so later Actions can
|
// Save this connection in the shared Data object so later Actions can
|
||||||
|
|
@ -109,7 +105,8 @@ void DBAction::RunOnTarget(
|
||||||
}
|
}
|
||||||
|
|
||||||
Result<nsCOMPtr<mozIStorageConnection>, nsresult> DBAction::OpenConnection(
|
Result<nsCOMPtr<mozIStorageConnection>, nsresult> DBAction::OpenConnection(
|
||||||
const CacheDirectoryMetadata& aDirectoryMetadata, nsIFile& aDBDir) {
|
const CacheDirectoryMetadata& aDirectoryMetadata, nsIFile& aDBDir,
|
||||||
|
const Maybe<CipherKey>& aMaybeCipherKey) {
|
||||||
MOZ_ASSERT(!NS_IsMainThread());
|
MOZ_ASSERT(!NS_IsMainThread());
|
||||||
MOZ_DIAGNOSTIC_ASSERT(aDirectoryMetadata.mDirectoryLockId >= 0);
|
MOZ_DIAGNOSTIC_ASSERT(aDirectoryMetadata.mDirectoryLockId >= 0);
|
||||||
|
|
||||||
|
|
@ -124,7 +121,7 @@ Result<nsCOMPtr<mozIStorageConnection>, nsresult> DBAction::OpenConnection(
|
||||||
QM_TRY_INSPECT(const auto& dbFile,
|
QM_TRY_INSPECT(const auto& dbFile,
|
||||||
CloneFileAndAppend(aDBDir, kCachesSQLiteFilename));
|
CloneFileAndAppend(aDBDir, kCachesSQLiteFilename));
|
||||||
|
|
||||||
QM_TRY_RETURN(OpenDBConnection(aDirectoryMetadata, *dbFile));
|
QM_TRY_RETURN(OpenDBConnection(aDirectoryMetadata, *dbFile, aMaybeCipherKey));
|
||||||
}
|
}
|
||||||
|
|
||||||
SyncDBAction::SyncDBAction(Mode aMode) : DBAction(aMode) {}
|
SyncDBAction::SyncDBAction(Mode aMode) : DBAction(aMode) {}
|
||||||
|
|
@ -145,9 +142,11 @@ void SyncDBAction::RunWithDBOnTarget(
|
||||||
}
|
}
|
||||||
|
|
||||||
Result<nsCOMPtr<mozIStorageConnection>, nsresult> OpenDBConnection(
|
Result<nsCOMPtr<mozIStorageConnection>, nsresult> OpenDBConnection(
|
||||||
const CacheDirectoryMetadata& aDirectoryMetadata, nsIFile& aDBFile) {
|
const CacheDirectoryMetadata& aDirectoryMetadata, nsIFile& aDBFile,
|
||||||
|
const Maybe<CipherKey>& aMaybeCipherKey) {
|
||||||
MOZ_ASSERT(!NS_IsMainThread());
|
MOZ_ASSERT(!NS_IsMainThread());
|
||||||
MOZ_DIAGNOSTIC_ASSERT(aDirectoryMetadata.mDirectoryLockId >= -1);
|
MOZ_DIAGNOSTIC_ASSERT(aDirectoryMetadata.mDirectoryLockId >= -1);
|
||||||
|
MOZ_DIAGNOSTIC_ASSERT_IF(aDirectoryMetadata.mIsPrivate, aMaybeCipherKey);
|
||||||
|
|
||||||
// Use our default file:// protocol handler directly to construct the database
|
// Use our default file:// protocol handler directly to construct the database
|
||||||
// URL. This avoids any problems if a plugin registers a custom file://
|
// URL. This avoids any problems if a plugin registers a custom file://
|
||||||
|
|
@ -166,10 +165,22 @@ Result<nsCOMPtr<mozIStorageConnection>, nsresult> OpenDBConnection(
|
||||||
IntToCString(aDirectoryMetadata.mDirectoryLockId)
|
IntToCString(aDirectoryMetadata.mDirectoryLockId)
|
||||||
: EmptyCString();
|
: EmptyCString();
|
||||||
|
|
||||||
|
const auto keyClause = [&aMaybeCipherKey] {
|
||||||
|
nsAutoCString keyClause;
|
||||||
|
if (aMaybeCipherKey) {
|
||||||
|
keyClause.AssignLiteral("&key=");
|
||||||
|
for (uint8_t byte : CipherStrategy::SerializeKey(*aMaybeCipherKey)) {
|
||||||
|
keyClause.AppendPrintf("%02x", byte);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return keyClause;
|
||||||
|
}();
|
||||||
|
|
||||||
nsCOMPtr<nsIFileURL> dbFileUrl;
|
nsCOMPtr<nsIFileURL> dbFileUrl;
|
||||||
QM_TRY(MOZ_TO_RESULT(NS_MutateURI(mutator)
|
QM_TRY(MOZ_TO_RESULT(
|
||||||
.SetQuery("cache=private"_ns + directoryLockIdClause)
|
NS_MutateURI(mutator)
|
||||||
.Finalize(dbFileUrl)));
|
.SetQuery("cache=private"_ns + directoryLockIdClause + keyClause)
|
||||||
|
.Finalize(dbFileUrl)));
|
||||||
|
|
||||||
QM_TRY_INSPECT(const auto& storageService,
|
QM_TRY_INSPECT(const auto& storageService,
|
||||||
MOZ_TO_RESULT_GET_TYPED(nsCOMPtr<mozIStorageService>,
|
MOZ_TO_RESULT_GET_TYPED(nsCOMPtr<mozIStorageService>,
|
||||||
|
|
|
||||||
10
dom/cache/DBAction.h
vendored
10
dom/cache/DBAction.h
vendored
|
|
@ -7,6 +7,7 @@
|
||||||
#ifndef mozilla_dom_cache_DBAction_h
|
#ifndef mozilla_dom_cache_DBAction_h
|
||||||
#define mozilla_dom_cache_DBAction_h
|
#define mozilla_dom_cache_DBAction_h
|
||||||
|
|
||||||
|
#include "CacheCipherKeyManager.h"
|
||||||
#include "mozilla/dom/cache/Action.h"
|
#include "mozilla/dom/cache/Action.h"
|
||||||
#include "mozilla/RefPtr.h"
|
#include "mozilla/RefPtr.h"
|
||||||
#include "nsString.h"
|
#include "nsString.h"
|
||||||
|
|
@ -17,7 +18,8 @@ class nsIFile;
|
||||||
namespace mozilla::dom::cache {
|
namespace mozilla::dom::cache {
|
||||||
|
|
||||||
Result<nsCOMPtr<mozIStorageConnection>, nsresult> OpenDBConnection(
|
Result<nsCOMPtr<mozIStorageConnection>, nsresult> OpenDBConnection(
|
||||||
const CacheDirectoryMetadata& aDirectoryMetadata, nsIFile& aDBFile);
|
const CacheDirectoryMetadata& aDirectoryMetadata, nsIFile& aDBFile,
|
||||||
|
const Maybe<CipherKey>& aMaybeCipherKey);
|
||||||
|
|
||||||
class DBAction : public Action {
|
class DBAction : public Action {
|
||||||
protected:
|
protected:
|
||||||
|
|
@ -41,10 +43,12 @@ class DBAction : public Action {
|
||||||
private:
|
private:
|
||||||
void RunOnTarget(SafeRefPtr<Resolver> aResolver,
|
void RunOnTarget(SafeRefPtr<Resolver> aResolver,
|
||||||
const Maybe<CacheDirectoryMetadata>& aDirectoryMetadata,
|
const Maybe<CacheDirectoryMetadata>& aDirectoryMetadata,
|
||||||
Data* aOptionalData) override;
|
Data* aOptionalData,
|
||||||
|
const Maybe<CipherKey>& aMaybeCipherKey) override;
|
||||||
|
|
||||||
Result<nsCOMPtr<mozIStorageConnection>, nsresult> OpenConnection(
|
Result<nsCOMPtr<mozIStorageConnection>, nsresult> OpenConnection(
|
||||||
const CacheDirectoryMetadata& aDirectoryMetadata, nsIFile& aDBDir);
|
const CacheDirectoryMetadata& aDirectoryMetadata, nsIFile& aDBDir,
|
||||||
|
const Maybe<CipherKey>& aMaybeCipherKey);
|
||||||
|
|
||||||
const Mode mMode;
|
const Mode mMode;
|
||||||
};
|
};
|
||||||
|
|
|
||||||
67
dom/cache/FileUtils.cpp
vendored
67
dom/cache/FileUtils.cpp
vendored
|
|
@ -6,9 +6,15 @@
|
||||||
|
|
||||||
#include "FileUtilsImpl.h"
|
#include "FileUtilsImpl.h"
|
||||||
|
|
||||||
|
#include "CacheCipherKeyManager.h"
|
||||||
#include "DBSchema.h"
|
#include "DBSchema.h"
|
||||||
#include "mozilla/dom/InternalResponse.h"
|
#include "mozilla/dom/InternalResponse.h"
|
||||||
|
#include "mozilla/dom/quota/DecryptingInputStream.h"
|
||||||
|
#include "mozilla/dom/quota/DecryptingInputStream_impl.h"
|
||||||
|
#include "mozilla/dom/quota/EncryptingOutputStream.h"
|
||||||
|
#include "mozilla/dom/quota/EncryptingOutputStream_impl.h"
|
||||||
#include "mozilla/dom/quota/FileStreams.h"
|
#include "mozilla/dom/quota/FileStreams.h"
|
||||||
|
#include "mozilla/dom/quota/PersistenceType.h"
|
||||||
#include "mozilla/dom/quota/QuotaManager.h"
|
#include "mozilla/dom/quota/QuotaManager.h"
|
||||||
#include "mozilla/dom/quota/QuotaObject.h"
|
#include "mozilla/dom/quota/QuotaObject.h"
|
||||||
#include "mozilla/dom/quota/ResultExtensions.h"
|
#include "mozilla/dom/quota/ResultExtensions.h"
|
||||||
|
|
@ -32,11 +38,8 @@ static_assert(SNAPPY_VERSION == 0x010109);
|
||||||
|
|
||||||
using mozilla::dom::quota::Client;
|
using mozilla::dom::quota::Client;
|
||||||
using mozilla::dom::quota::CloneFileAndAppend;
|
using mozilla::dom::quota::CloneFileAndAppend;
|
||||||
using mozilla::dom::quota::FileInputStream;
|
|
||||||
using mozilla::dom::quota::FileOutputStream;
|
|
||||||
using mozilla::dom::quota::GetDirEntryKind;
|
using mozilla::dom::quota::GetDirEntryKind;
|
||||||
using mozilla::dom::quota::nsIFileKind;
|
using mozilla::dom::quota::nsIFileKind;
|
||||||
using mozilla::dom::quota::PERSISTENCE_TYPE_DEFAULT;
|
|
||||||
using mozilla::dom::quota::QuotaManager;
|
using mozilla::dom::quota::QuotaManager;
|
||||||
using mozilla::dom::quota::QuotaObject;
|
using mozilla::dom::quota::QuotaObject;
|
||||||
|
|
||||||
|
|
@ -46,6 +49,12 @@ namespace {
|
||||||
// XXX This will be tweaked to something more meaningful in Bug 1383656.
|
// XXX This will be tweaked to something more meaningful in Bug 1383656.
|
||||||
const int64_t kRoundUpNumber = 20480;
|
const int64_t kRoundUpNumber = 20480;
|
||||||
|
|
||||||
|
// At the moment, the encrypted stream block size is assumed to be unchangeable
|
||||||
|
// between encrypting and decrypting blobs. This assumptions holds as long as we
|
||||||
|
// only encrypt in private browsing mode, but when we support encryption for
|
||||||
|
// persistent storage, this needs to be changed.
|
||||||
|
constexpr uint32_t kEncryptedStreamBlockSize = 4096;
|
||||||
|
|
||||||
enum BodyFileType { BODY_FILE_FINAL, BODY_FILE_TMP };
|
enum BodyFileType { BODY_FILE_FINAL, BODY_FILE_TMP };
|
||||||
|
|
||||||
Result<NotNull<nsCOMPtr<nsIFile>>, nsresult> BodyIdToFile(nsIFile& aBaseDir,
|
Result<NotNull<nsCOMPtr<nsIFile>>, nsresult> BodyIdToFile(nsIFile& aBaseDir,
|
||||||
|
|
@ -128,22 +137,15 @@ nsresult BodyDeleteDir(const CacheDirectoryMetadata& aDirectoryMetadata,
|
||||||
return NS_OK;
|
return NS_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
Result<std::pair<nsID, nsCOMPtr<nsISupports>>, nsresult> BodyStartWriteStream(
|
Result<nsCOMPtr<nsISupports>, nsresult> BodyStartWriteStream(
|
||||||
const CacheDirectoryMetadata& aDirectoryMetadata, nsIFile& aBaseDir,
|
const CacheDirectoryMetadata& aDirectoryMetadata, nsIFile& aBaseDir,
|
||||||
|
const nsID& aBodyId, Maybe<CipherKey> aMaybeCipherKey,
|
||||||
nsIInputStream& aSource, void* aClosure, nsAsyncCopyCallbackFun aCallback) {
|
nsIInputStream& aSource, void* aClosure, nsAsyncCopyCallbackFun aCallback) {
|
||||||
MOZ_DIAGNOSTIC_ASSERT(aClosure);
|
MOZ_DIAGNOSTIC_ASSERT(aClosure);
|
||||||
MOZ_DIAGNOSTIC_ASSERT(aCallback);
|
MOZ_DIAGNOSTIC_ASSERT(aCallback);
|
||||||
|
|
||||||
QM_TRY_INSPECT(const auto& idGen,
|
|
||||||
MOZ_TO_RESULT_GET_TYPED(nsCOMPtr<nsIUUIDGenerator>,
|
|
||||||
MOZ_SELECT_OVERLOAD(do_GetService),
|
|
||||||
"@mozilla.org/uuid-generator;1"));
|
|
||||||
|
|
||||||
nsID id;
|
|
||||||
QM_TRY(MOZ_TO_RESULT(idGen->GenerateUUIDInPlace(&id)));
|
|
||||||
|
|
||||||
QM_TRY_INSPECT(const auto& finalFile,
|
QM_TRY_INSPECT(const auto& finalFile,
|
||||||
BodyIdToFile(aBaseDir, id, BODY_FILE_FINAL));
|
BodyIdToFile(aBaseDir, aBodyId, BODY_FILE_FINAL));
|
||||||
|
|
||||||
{
|
{
|
||||||
QM_TRY_INSPECT(const bool& exists,
|
QM_TRY_INSPECT(const bool& exists,
|
||||||
|
|
@ -153,12 +155,20 @@ Result<std::pair<nsID, nsCOMPtr<nsISupports>>, nsresult> BodyStartWriteStream(
|
||||||
}
|
}
|
||||||
|
|
||||||
QM_TRY_INSPECT(const auto& tmpFile,
|
QM_TRY_INSPECT(const auto& tmpFile,
|
||||||
BodyIdToFile(aBaseDir, id, BODY_FILE_TMP));
|
BodyIdToFile(aBaseDir, aBodyId, BODY_FILE_TMP));
|
||||||
|
|
||||||
QM_TRY_UNWRAP(
|
QM_TRY_UNWRAP(nsCOMPtr<nsIOutputStream> fileStream,
|
||||||
nsCOMPtr<nsIOutputStream> fileStream,
|
CreateFileOutputStream(aDirectoryMetadata.mPersistenceType,
|
||||||
CreateFileOutputStream(PERSISTENCE_TYPE_DEFAULT, aDirectoryMetadata,
|
aDirectoryMetadata, Client::DOMCACHE,
|
||||||
Client::DOMCACHE, tmpFile.get()));
|
tmpFile.get()));
|
||||||
|
|
||||||
|
const auto privateBody = aDirectoryMetadata.mIsPrivate;
|
||||||
|
if (privateBody) {
|
||||||
|
MOZ_DIAGNOSTIC_ASSERT(aMaybeCipherKey);
|
||||||
|
|
||||||
|
fileStream = MakeRefPtr<quota::EncryptingOutputStream<CipherStrategy>>(
|
||||||
|
std::move(fileStream), kEncryptedStreamBlockSize, *aMaybeCipherKey);
|
||||||
|
}
|
||||||
|
|
||||||
const auto compressed = MakeRefPtr<SnappyCompressOutputStream>(fileStream);
|
const auto compressed = MakeRefPtr<SnappyCompressOutputStream>(fileStream);
|
||||||
|
|
||||||
|
|
@ -172,7 +182,7 @@ Result<std::pair<nsID, nsCOMPtr<nsISupports>>, nsresult> BodyStartWriteStream(
|
||||||
true, // close streams
|
true, // close streams
|
||||||
getter_AddRefs(copyContext))));
|
getter_AddRefs(copyContext))));
|
||||||
|
|
||||||
return std::make_pair(id, std::move(copyContext));
|
return std::move(copyContext);
|
||||||
}
|
}
|
||||||
|
|
||||||
void BodyCancelWrite(nsISupports& aCopyContext) {
|
void BodyCancelWrite(nsISupports& aCopyContext) {
|
||||||
|
|
@ -203,13 +213,24 @@ nsresult BodyFinalizeWrite(nsIFile& aBaseDir, const nsID& aId) {
|
||||||
|
|
||||||
Result<MovingNotNull<nsCOMPtr<nsIInputStream>>, nsresult> BodyOpen(
|
Result<MovingNotNull<nsCOMPtr<nsIInputStream>>, nsresult> BodyOpen(
|
||||||
const CacheDirectoryMetadata& aDirectoryMetadata, nsIFile& aBaseDir,
|
const CacheDirectoryMetadata& aDirectoryMetadata, nsIFile& aBaseDir,
|
||||||
const nsID& aId) {
|
const nsID& aId, Maybe<CipherKey> aMaybeCipherKey) {
|
||||||
QM_TRY_INSPECT(const auto& finalFile,
|
QM_TRY_INSPECT(const auto& finalFile,
|
||||||
BodyIdToFile(aBaseDir, aId, BODY_FILE_FINAL));
|
BodyIdToFile(aBaseDir, aId, BODY_FILE_FINAL));
|
||||||
|
|
||||||
QM_TRY_RETURN(CreateFileInputStream(PERSISTENCE_TYPE_DEFAULT,
|
QM_TRY_UNWRAP(nsCOMPtr<nsIInputStream> fileInputStream,
|
||||||
|
CreateFileInputStream(aDirectoryMetadata.mPersistenceType,
|
||||||
aDirectoryMetadata, Client::DOMCACHE,
|
aDirectoryMetadata, Client::DOMCACHE,
|
||||||
finalFile.get()));
|
finalFile.get()));
|
||||||
|
|
||||||
|
auto privateBody = aDirectoryMetadata.mIsPrivate;
|
||||||
|
if (privateBody) {
|
||||||
|
MOZ_DIAGNOSTIC_ASSERT(aMaybeCipherKey);
|
||||||
|
|
||||||
|
fileInputStream = new quota::DecryptingInputStream<CipherStrategy>(
|
||||||
|
WrapNotNull(std::move(fileInputStream)), kEncryptedStreamBlockSize,
|
||||||
|
*aMaybeCipherKey);
|
||||||
|
}
|
||||||
|
return WrapMovingNotNull(std::move(fileInputStream));
|
||||||
}
|
}
|
||||||
|
|
||||||
nsresult BodyMaybeUpdatePaddingSize(
|
nsresult BodyMaybeUpdatePaddingSize(
|
||||||
|
|
@ -225,7 +246,7 @@ nsresult BodyMaybeUpdatePaddingSize(
|
||||||
|
|
||||||
int64_t fileSize = 0;
|
int64_t fileSize = 0;
|
||||||
RefPtr<QuotaObject> quotaObject = quotaManager->GetQuotaObject(
|
RefPtr<QuotaObject> quotaObject = quotaManager->GetQuotaObject(
|
||||||
PERSISTENCE_TYPE_DEFAULT, aDirectoryMetadata, Client::DOMCACHE,
|
aDirectoryMetadata.mPersistenceType, aDirectoryMetadata, Client::DOMCACHE,
|
||||||
bodyFile.get(), -1, &fileSize);
|
bodyFile.get(), -1, &fileSize);
|
||||||
MOZ_DIAGNOSTIC_ASSERT(quotaObject);
|
MOZ_DIAGNOSTIC_ASSERT(quotaObject);
|
||||||
MOZ_DIAGNOSTIC_ASSERT(fileSize >= 0);
|
MOZ_DIAGNOSTIC_ASSERT(fileSize >= 0);
|
||||||
|
|
@ -256,7 +277,7 @@ nsresult BodyDeleteFiles(const CacheDirectoryMetadata& aDirectoryMetadata,
|
||||||
[&aDirectoryMetadata, &id](
|
[&aDirectoryMetadata, &id](
|
||||||
nsIFile& bodyFile,
|
nsIFile& bodyFile,
|
||||||
const nsACString& leafName) -> Result<bool, nsresult> {
|
const nsACString& leafName) -> Result<bool, nsresult> {
|
||||||
nsID fileId;
|
nsID fileId{};
|
||||||
QM_TRY(OkIf(fileId.Parse(leafName.BeginReading())), true,
|
QM_TRY(OkIf(fileId.Parse(leafName.BeginReading())), true,
|
||||||
([&aDirectoryMetadata, &bodyFile](const auto) {
|
([&aDirectoryMetadata, &bodyFile](const auto) {
|
||||||
DebugOnly<nsresult> result = RemoveNsIFile(
|
DebugOnly<nsresult> result = RemoveNsIFile(
|
||||||
|
|
|
||||||
8
dom/cache/FileUtils.h
vendored
8
dom/cache/FileUtils.h
vendored
|
|
@ -7,9 +7,10 @@
|
||||||
#ifndef mozilla_dom_cache_FileUtils_h
|
#ifndef mozilla_dom_cache_FileUtils_h
|
||||||
#define mozilla_dom_cache_FileUtils_h
|
#define mozilla_dom_cache_FileUtils_h
|
||||||
|
|
||||||
|
#include "CacheCommon.h"
|
||||||
|
#include "CacheCipherKeyManager.h"
|
||||||
#include "mozilla/Attributes.h"
|
#include "mozilla/Attributes.h"
|
||||||
#include "mozilla/dom/cache/Types.h"
|
#include "mozilla/dom/cache/Types.h"
|
||||||
#include "CacheCommon.h"
|
|
||||||
#include "mozIStorageConnection.h"
|
#include "mozIStorageConnection.h"
|
||||||
#include "nsStreamUtils.h"
|
#include "nsStreamUtils.h"
|
||||||
#include "nsTArrayForwardDeclare.h"
|
#include "nsTArrayForwardDeclare.h"
|
||||||
|
|
@ -34,8 +35,9 @@ nsresult BodyDeleteDir(const CacheDirectoryMetadata& aDirectoryMetadata,
|
||||||
|
|
||||||
// Returns a Result with a success value with the body id and, optionally, the
|
// Returns a Result with a success value with the body id and, optionally, the
|
||||||
// copy context.
|
// copy context.
|
||||||
Result<std::pair<nsID, nsCOMPtr<nsISupports>>, nsresult> BodyStartWriteStream(
|
Result<nsCOMPtr<nsISupports>, nsresult> BodyStartWriteStream(
|
||||||
const CacheDirectoryMetadata& aDirectoryMetadata, nsIFile& aBaseDir,
|
const CacheDirectoryMetadata& aDirectoryMetadata, nsIFile& aBaseDir,
|
||||||
|
const nsID& aBodyId, Maybe<CipherKey> aMaybeCipherKey,
|
||||||
nsIInputStream& aSource, void* aClosure, nsAsyncCopyCallbackFun aCallback);
|
nsIInputStream& aSource, void* aClosure, nsAsyncCopyCallbackFun aCallback);
|
||||||
|
|
||||||
void BodyCancelWrite(nsISupports& aCopyContext);
|
void BodyCancelWrite(nsISupports& aCopyContext);
|
||||||
|
|
@ -44,7 +46,7 @@ nsresult BodyFinalizeWrite(nsIFile& aBaseDir, const nsID& aId);
|
||||||
|
|
||||||
Result<MovingNotNull<nsCOMPtr<nsIInputStream>>, nsresult> BodyOpen(
|
Result<MovingNotNull<nsCOMPtr<nsIInputStream>>, nsresult> BodyOpen(
|
||||||
const CacheDirectoryMetadata& aDirectoryMetadata, nsIFile& aBaseDir,
|
const CacheDirectoryMetadata& aDirectoryMetadata, nsIFile& aBaseDir,
|
||||||
const nsID& aId);
|
const nsID& aId, Maybe<CipherKey> aMaybeCipherKey);
|
||||||
|
|
||||||
nsresult BodyMaybeUpdatePaddingSize(
|
nsresult BodyMaybeUpdatePaddingSize(
|
||||||
const CacheDirectoryMetadata& aDirectoryMetadata, nsIFile& aBaseDir,
|
const CacheDirectoryMetadata& aDirectoryMetadata, nsIFile& aBaseDir,
|
||||||
|
|
|
||||||
89
dom/cache/Manager.cpp
vendored
89
dom/cache/Manager.cpp
vendored
|
|
@ -7,6 +7,7 @@
|
||||||
#include "mozilla/dom/cache/Manager.h"
|
#include "mozilla/dom/cache/Manager.h"
|
||||||
|
|
||||||
#include "mozilla/AppShutdown.h"
|
#include "mozilla/AppShutdown.h"
|
||||||
|
#include "mozilla/Assertions.h"
|
||||||
#include "mozilla/AutoRestore.h"
|
#include "mozilla/AutoRestore.h"
|
||||||
#include "mozilla/Mutex.h"
|
#include "mozilla/Mutex.h"
|
||||||
#include "mozilla/StaticMutex.h"
|
#include "mozilla/StaticMutex.h"
|
||||||
|
|
@ -30,13 +31,14 @@
|
||||||
#include "nsID.h"
|
#include "nsID.h"
|
||||||
#include "nsIFile.h"
|
#include "nsIFile.h"
|
||||||
#include "nsIThread.h"
|
#include "nsIThread.h"
|
||||||
|
#include "nsIUUIDGenerator.h"
|
||||||
#include "nsThreadUtils.h"
|
#include "nsThreadUtils.h"
|
||||||
#include "nsTObserverArray.h"
|
#include "nsTObserverArray.h"
|
||||||
#include "QuotaClientImpl.h"
|
#include "QuotaClientImpl.h"
|
||||||
|
#include "Types.h"
|
||||||
|
|
||||||
namespace mozilla::dom::cache {
|
namespace mozilla::dom::cache {
|
||||||
|
|
||||||
using mozilla::dom::quota::Client;
|
|
||||||
using mozilla::dom::quota::CloneFileAndAppend;
|
using mozilla::dom::quota::CloneFileAndAppend;
|
||||||
using mozilla::dom::quota::DirectoryLock;
|
using mozilla::dom::quota::DirectoryLock;
|
||||||
|
|
||||||
|
|
@ -67,6 +69,24 @@ nsresult MaybeUpdatePaddingFile(nsIFile* aBaseDir, mozIStorageConnection* aConn,
|
||||||
return NS_OK;
|
return NS_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Maybe<CipherKey> GetOrCreateCipherKey(NotNull<Context*> aContext,
|
||||||
|
const nsID& aBodyId, bool aCreate) {
|
||||||
|
const auto& maybeMetadata = aContext->MaybeCacheDirectoryMetadataRef();
|
||||||
|
MOZ_DIAGNOSTIC_ASSERT(maybeMetadata);
|
||||||
|
|
||||||
|
auto privateOrigin = maybeMetadata->mIsPrivate;
|
||||||
|
if (!privateOrigin) {
|
||||||
|
return Nothing{};
|
||||||
|
}
|
||||||
|
|
||||||
|
nsCString bodyIdStr{aBodyId.ToString().get()};
|
||||||
|
|
||||||
|
auto& cipherKeyManager = aContext->MutableCipherKeyManagerRef();
|
||||||
|
|
||||||
|
return aCreate ? Some(cipherKeyManager.Ensure(bodyIdStr))
|
||||||
|
: cipherKeyManager.Get(bodyIdStr);
|
||||||
|
}
|
||||||
|
|
||||||
// An Action that is executed when a Context is first created. It ensures that
|
// An Action that is executed when a Context is first created. It ensures that
|
||||||
// the directory and database are setup properly. This lets other actions
|
// the directory and database are setup properly. This lets other actions
|
||||||
// not worry about these details.
|
// not worry about these details.
|
||||||
|
|
@ -173,7 +193,8 @@ class DeleteOrphanedBodyAction final : public Action {
|
||||||
|
|
||||||
void RunOnTarget(SafeRefPtr<Resolver> aResolver,
|
void RunOnTarget(SafeRefPtr<Resolver> aResolver,
|
||||||
const Maybe<CacheDirectoryMetadata>& aDirectoryMetadata,
|
const Maybe<CacheDirectoryMetadata>& aDirectoryMetadata,
|
||||||
Data*) override {
|
Data*,
|
||||||
|
const Maybe<CipherKey>& /*aMaybeCipherKey*/) override {
|
||||||
MOZ_DIAGNOSTIC_ASSERT(aResolver);
|
MOZ_DIAGNOSTIC_ASSERT(aResolver);
|
||||||
MOZ_DIAGNOSTIC_ASSERT(aDirectoryMetadata);
|
MOZ_DIAGNOSTIC_ASSERT(aDirectoryMetadata);
|
||||||
MOZ_DIAGNOSTIC_ASSERT(aDirectoryMetadata->mDir);
|
MOZ_DIAGNOSTIC_ASSERT(aDirectoryMetadata->mDir);
|
||||||
|
|
@ -635,10 +656,15 @@ class Manager::CacheMatchAction final : public Manager::BaseAction {
|
||||||
return NS_OK;
|
return NS_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const auto& bodyId = mResponse.mBodyId;
|
||||||
|
|
||||||
nsCOMPtr<nsIInputStream> stream;
|
nsCOMPtr<nsIInputStream> stream;
|
||||||
if (mArgs.openMode() == OpenMode::Eager) {
|
if (mArgs.openMode() == OpenMode::Eager) {
|
||||||
QM_TRY_UNWRAP(stream,
|
QM_TRY_UNWRAP(
|
||||||
BodyOpen(aDirectoryMetadata, *aDBDir, mResponse.mBodyId));
|
stream,
|
||||||
|
BodyOpen(aDirectoryMetadata, *aDBDir, bodyId,
|
||||||
|
GetOrCreateCipherKey(WrapNotNull(mManager->mContext), bodyId,
|
||||||
|
/* aCreate */ false)));
|
||||||
}
|
}
|
||||||
|
|
||||||
mStreamList->Add(mResponse.mBodyId, std::move(stream));
|
mStreamList->Add(mResponse.mBodyId, std::move(stream));
|
||||||
|
|
@ -697,10 +723,15 @@ class Manager::CacheMatchAllAction final : public Manager::BaseAction {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const auto& bodyId = mSavedResponses[i].mBodyId;
|
||||||
|
|
||||||
nsCOMPtr<nsIInputStream> stream;
|
nsCOMPtr<nsIInputStream> stream;
|
||||||
if (mArgs.openMode() == OpenMode::Eager) {
|
if (mArgs.openMode() == OpenMode::Eager) {
|
||||||
QM_TRY_UNWRAP(stream, BodyOpen(aDirectoryMetadata, *aDBDir,
|
QM_TRY_UNWRAP(stream,
|
||||||
mSavedResponses[i].mBodyId));
|
BodyOpen(aDirectoryMetadata, *aDBDir, bodyId,
|
||||||
|
GetOrCreateCipherKey(
|
||||||
|
WrapNotNull(mManager->mContext), bodyId,
|
||||||
|
/* aCreate */ false)));
|
||||||
}
|
}
|
||||||
|
|
||||||
mStreamList->Add(mSavedResponses[i].mBodyId, std::move(stream));
|
mStreamList->Add(mSavedResponses[i].mBodyId, std::move(stream));
|
||||||
|
|
@ -971,12 +1002,12 @@ class Manager::CachePutAllAction final : public DBAction {
|
||||||
struct Entry {
|
struct Entry {
|
||||||
CacheRequest mRequest;
|
CacheRequest mRequest;
|
||||||
nsCOMPtr<nsIInputStream> mRequestStream;
|
nsCOMPtr<nsIInputStream> mRequestStream;
|
||||||
nsID mRequestBodyId;
|
nsID mRequestBodyId{};
|
||||||
nsCOMPtr<nsISupports> mRequestCopyContext;
|
nsCOMPtr<nsISupports> mRequestCopyContext;
|
||||||
|
|
||||||
CacheResponse mResponse;
|
CacheResponse mResponse;
|
||||||
nsCOMPtr<nsIInputStream> mResponseStream;
|
nsCOMPtr<nsIInputStream> mResponseStream;
|
||||||
nsID mResponseBodyId;
|
nsID mResponseBodyId{};
|
||||||
nsCOMPtr<nsISupports> mResponseCopyContext;
|
nsCOMPtr<nsISupports> mResponseCopyContext;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
@ -1001,10 +1032,22 @@ class Manager::CachePutAllAction final : public DBAction {
|
||||||
if (!source) {
|
if (!source) {
|
||||||
return NS_OK;
|
return NS_OK;
|
||||||
}
|
}
|
||||||
|
QM_TRY_INSPECT(const auto& idGen,
|
||||||
|
MOZ_TO_RESULT_GET_TYPED(nsCOMPtr<nsIUUIDGenerator>,
|
||||||
|
MOZ_SELECT_OVERLOAD(do_GetService),
|
||||||
|
"@mozilla.org/uuid-generator;1"));
|
||||||
|
|
||||||
QM_TRY_INSPECT((const auto& [bodyId, copyContext]),
|
nsID bodyId{};
|
||||||
BodyStartWriteStream(aDirectoryMetadata, *mDBDir, *source,
|
QM_TRY(MOZ_TO_RESULT(idGen->GenerateUUIDInPlace(&bodyId)));
|
||||||
this, AsyncCopyCompleteFunc));
|
|
||||||
|
Maybe<CipherKey> maybeKey =
|
||||||
|
GetOrCreateCipherKey(WrapNotNull(mManager->mContext), bodyId,
|
||||||
|
/* aCreate */ true);
|
||||||
|
|
||||||
|
QM_TRY_INSPECT(
|
||||||
|
const auto& copyContext,
|
||||||
|
BodyStartWriteStream(aDirectoryMetadata, *mDBDir, bodyId, maybeKey,
|
||||||
|
*source, this, AsyncCopyCompleteFunc));
|
||||||
|
|
||||||
if (aStreamId == RequestStream) {
|
if (aStreamId == RequestStream) {
|
||||||
aEntry.mRequestBodyId = bodyId;
|
aEntry.mRequestBodyId = bodyId;
|
||||||
|
|
@ -1218,10 +1261,15 @@ class Manager::CacheKeysAction final : public Manager::BaseAction {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const auto& bodyId = mSavedRequests[i].mBodyId;
|
||||||
|
|
||||||
nsCOMPtr<nsIInputStream> stream;
|
nsCOMPtr<nsIInputStream> stream;
|
||||||
if (mArgs.openMode() == OpenMode::Eager) {
|
if (mArgs.openMode() == OpenMode::Eager) {
|
||||||
QM_TRY_UNWRAP(stream, BodyOpen(aDirectoryMetadata, *aDBDir,
|
QM_TRY_UNWRAP(stream,
|
||||||
mSavedRequests[i].mBodyId));
|
BodyOpen(aDirectoryMetadata, *aDBDir, bodyId,
|
||||||
|
GetOrCreateCipherKey(
|
||||||
|
WrapNotNull(mManager->mContext), bodyId,
|
||||||
|
/* aCreate */ false)));
|
||||||
}
|
}
|
||||||
|
|
||||||
mStreamList->Add(mSavedRequests[i].mBodyId, std::move(stream));
|
mStreamList->Add(mSavedRequests[i].mBodyId, std::move(stream));
|
||||||
|
|
@ -1283,10 +1331,15 @@ class Manager::StorageMatchAction final : public Manager::BaseAction {
|
||||||
return NS_OK;
|
return NS_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const auto& bodyId = mSavedResponse.mBodyId;
|
||||||
|
|
||||||
nsCOMPtr<nsIInputStream> stream;
|
nsCOMPtr<nsIInputStream> stream;
|
||||||
if (mArgs.openMode() == OpenMode::Eager) {
|
if (mArgs.openMode() == OpenMode::Eager) {
|
||||||
QM_TRY_UNWRAP(stream, BodyOpen(aDirectoryMetadata, *aDBDir,
|
QM_TRY_UNWRAP(
|
||||||
mSavedResponse.mBodyId));
|
stream,
|
||||||
|
BodyOpen(aDirectoryMetadata, *aDBDir, bodyId,
|
||||||
|
GetOrCreateCipherKey(WrapNotNull(mManager->mContext), bodyId,
|
||||||
|
/* aCreate */ false)));
|
||||||
}
|
}
|
||||||
|
|
||||||
mStreamList->Add(mSavedResponse.mBodyId, std::move(stream));
|
mStreamList->Add(mSavedResponse.mBodyId, std::move(stream));
|
||||||
|
|
@ -1511,7 +1564,11 @@ class Manager::OpenStreamAction final : public Manager::BaseAction {
|
||||||
mozIStorageConnection* aConn) override {
|
mozIStorageConnection* aConn) override {
|
||||||
MOZ_DIAGNOSTIC_ASSERT(aDBDir);
|
MOZ_DIAGNOSTIC_ASSERT(aDBDir);
|
||||||
|
|
||||||
QM_TRY_UNWRAP(mBodyStream, BodyOpen(aDirectoryMetadata, *aDBDir, mBodyId));
|
QM_TRY_UNWRAP(
|
||||||
|
mBodyStream,
|
||||||
|
BodyOpen(aDirectoryMetadata, *aDBDir, mBodyId,
|
||||||
|
GetOrCreateCipherKey(WrapNotNull(mManager->mContext), mBodyId,
|
||||||
|
/* aCreate */ false)));
|
||||||
|
|
||||||
return NS_OK;
|
return NS_OK;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
52
dom/cache/QuotaClient.cpp
vendored
52
dom/cache/QuotaClient.cpp
vendored
|
|
@ -8,11 +8,13 @@
|
||||||
|
|
||||||
#include "DBAction.h"
|
#include "DBAction.h"
|
||||||
#include "FileUtilsImpl.h"
|
#include "FileUtilsImpl.h"
|
||||||
|
#include "mozilla/DebugOnly.h"
|
||||||
#include "mozilla/ResultExtensions.h"
|
#include "mozilla/ResultExtensions.h"
|
||||||
#include "mozilla/Telemetry.h"
|
#include "mozilla/Telemetry.h"
|
||||||
#include "mozilla/Unused.h"
|
#include "mozilla/Unused.h"
|
||||||
#include "mozilla/dom/cache/DBSchema.h"
|
#include "mozilla/dom/cache/DBSchema.h"
|
||||||
#include "mozilla/dom/cache/Manager.h"
|
#include "mozilla/dom/cache/Manager.h"
|
||||||
|
#include "mozilla/dom/quota/PersistenceType.h"
|
||||||
#include "mozilla/dom/quota/QuotaCommon.h"
|
#include "mozilla/dom/quota/QuotaCommon.h"
|
||||||
#include "mozilla/dom/quota/QuotaManager.h"
|
#include "mozilla/dom/quota/QuotaManager.h"
|
||||||
#include "mozilla/dom/quota/UsageInfo.h"
|
#include "mozilla/dom/quota/UsageInfo.h"
|
||||||
|
|
@ -29,8 +31,7 @@ using mozilla::dom::quota::DatabaseUsageType;
|
||||||
using mozilla::dom::quota::GetDirEntryKind;
|
using mozilla::dom::quota::GetDirEntryKind;
|
||||||
using mozilla::dom::quota::nsIFileKind;
|
using mozilla::dom::quota::nsIFileKind;
|
||||||
using mozilla::dom::quota::OriginMetadata;
|
using mozilla::dom::quota::OriginMetadata;
|
||||||
using mozilla::dom::quota::PERSISTENCE_TYPE_DEFAULT;
|
using mozilla::dom::quota::PrincipalMetadata;
|
||||||
using mozilla::dom::quota::PersistenceType;
|
|
||||||
using mozilla::dom::quota::QuotaManager;
|
using mozilla::dom::quota::QuotaManager;
|
||||||
using mozilla::dom::quota::UsageInfo;
|
using mozilla::dom::quota::UsageInfo;
|
||||||
using mozilla::ipc::AssertIsOnBackgroundThread;
|
using mozilla::ipc::AssertIsOnBackgroundThread;
|
||||||
|
|
@ -123,7 +124,8 @@ Result<UsageInfo, nsresult> GetBodyUsage(nsIFile& aMorgueDir,
|
||||||
}
|
}
|
||||||
|
|
||||||
Result<int64_t, nsresult> GetPaddingSizeFromDB(
|
Result<int64_t, nsresult> GetPaddingSizeFromDB(
|
||||||
nsIFile& aDir, nsIFile& aDBFile, const OriginMetadata& aOriginMetadata) {
|
nsIFile& aDir, nsIFile& aDBFile, const OriginMetadata& aOriginMetadata,
|
||||||
|
const Maybe<CipherKey>& aMaybeCipherKey) {
|
||||||
CacheDirectoryMetadata directoryMetadata(aOriginMetadata);
|
CacheDirectoryMetadata directoryMetadata(aOriginMetadata);
|
||||||
// directoryMetadata.mDirectoryLockId must be -1 (which is default for new
|
// directoryMetadata.mDirectoryLockId must be -1 (which is default for new
|
||||||
// CacheDirectoryMetadata) because this method should only be called from
|
// CacheDirectoryMetadata) because this method should only be called from
|
||||||
|
|
@ -142,7 +144,7 @@ Result<int64_t, nsresult> GetPaddingSizeFromDB(
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
QM_TRY_INSPECT(const auto& conn,
|
QM_TRY_INSPECT(const auto& conn,
|
||||||
OpenDBConnection(directoryMetadata, aDBFile));
|
OpenDBConnection(directoryMetadata, aDBFile, aMaybeCipherKey));
|
||||||
|
|
||||||
// Make sure that the database has the latest schema before we try to read
|
// Make sure that the database has the latest schema before we try to read
|
||||||
// from it. We have to do this because GetPaddingSizeFromDB is called
|
// from it. We have to do this because GetPaddingSizeFromDB is called
|
||||||
|
|
@ -236,10 +238,19 @@ Result<UsageInfo, nsresult> CacheQuotaClient::InitOrigin(
|
||||||
// XXX Ensure the -wel file is removed if the caches.sqlite doesn't exist.
|
// XXX Ensure the -wel file is removed if the caches.sqlite doesn't exist.
|
||||||
QM_TRY(OkIf(!!cachesSQLiteFile), UsageInfo{});
|
QM_TRY(OkIf(!!cachesSQLiteFile), UsageInfo{});
|
||||||
|
|
||||||
|
const auto maybeCipherKey = [this, &aOriginMetadata] {
|
||||||
|
Maybe<CipherKey> maybeCipherKey;
|
||||||
|
auto cipherKeyManager = GetOrCreateCipherKeyManager(aOriginMetadata);
|
||||||
|
if (cipherKeyManager) {
|
||||||
|
maybeCipherKey = Some(cipherKeyManager->Ensure());
|
||||||
|
}
|
||||||
|
return maybeCipherKey;
|
||||||
|
}();
|
||||||
|
|
||||||
QM_TRY_INSPECT(
|
QM_TRY_INSPECT(
|
||||||
const auto& paddingSize,
|
const auto& paddingSize,
|
||||||
([dir, cachesSQLiteFile,
|
([dir, cachesSQLiteFile, &aOriginMetadata,
|
||||||
&aOriginMetadata]() -> Result<int64_t, nsresult> {
|
&maybeCipherKey]() -> Result<int64_t, nsresult> {
|
||||||
if (!DirectoryPaddingFileExists(*dir, DirPaddingFile::TMP_FILE)) {
|
if (!DirectoryPaddingFileExists(*dir, DirPaddingFile::TMP_FILE)) {
|
||||||
QM_WARNONLY_TRY_UNWRAP(const auto maybePaddingSize,
|
QM_WARNONLY_TRY_UNWRAP(const auto maybePaddingSize,
|
||||||
DirectoryPaddingGet(*dir));
|
DirectoryPaddingGet(*dir));
|
||||||
|
|
@ -251,8 +262,8 @@ Result<UsageInfo, nsresult> CacheQuotaClient::InitOrigin(
|
||||||
// If the temporary file still exists or failing to get the padding size
|
// If the temporary file still exists or failing to get the padding size
|
||||||
// from the padding file, then we need to get the padding size from the
|
// from the padding file, then we need to get the padding size from the
|
||||||
// database and restore the padding file.
|
// database and restore the padding file.
|
||||||
QM_TRY_RETURN(
|
QM_TRY_RETURN(GetPaddingSizeFromDB(*dir, *cachesSQLiteFile,
|
||||||
GetPaddingSizeFromDB(*dir, *cachesSQLiteFile, aOriginMetadata));
|
aOriginMetadata, maybeCipherKey));
|
||||||
}()));
|
}()));
|
||||||
|
|
||||||
QM_TRY_INSPECT(
|
QM_TRY_INSPECT(
|
||||||
|
|
@ -343,13 +354,20 @@ Result<UsageInfo, nsresult> CacheQuotaClient::GetUsageForOrigin(
|
||||||
QuotaManager* quotaManager = QuotaManager::Get();
|
QuotaManager* quotaManager = QuotaManager::Get();
|
||||||
MOZ_ASSERT(quotaManager);
|
MOZ_ASSERT(quotaManager);
|
||||||
|
|
||||||
return quotaManager->GetUsageForClient(PERSISTENCE_TYPE_DEFAULT,
|
return quotaManager->GetUsageForClient(aOriginMetadata.mPersistenceType,
|
||||||
aOriginMetadata, Client::DOMCACHE);
|
aOriginMetadata, Client::DOMCACHE);
|
||||||
}
|
}
|
||||||
|
|
||||||
void CacheQuotaClient::OnOriginClearCompleted(PersistenceType aPersistenceType,
|
void CacheQuotaClient::OnOriginClearCompleted(PersistenceType aPersistenceType,
|
||||||
const nsACString& aOrigin) {
|
const nsACString& aOrigin) {
|
||||||
// Nothing to do here.
|
AssertIsOnIOThread();
|
||||||
|
|
||||||
|
if (aPersistenceType == quota::PERSISTENCE_TYPE_PRIVATE) {
|
||||||
|
if (auto entry = mCipherKeyManagers.Lookup(aOrigin)) {
|
||||||
|
entry.Data()->Invalidate();
|
||||||
|
entry.Remove();
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void CacheQuotaClient::OnRepositoryClearCompleted(
|
void CacheQuotaClient::OnRepositoryClearCompleted(
|
||||||
|
|
@ -492,6 +510,20 @@ nsresult CacheQuotaClient::WipePaddingFileInternal(
|
||||||
return NS_OK;
|
return NS_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
RefPtr<CipherKeyManager> CacheQuotaClient::GetOrCreateCipherKeyManager(
|
||||||
|
const PrincipalMetadata& aMetadata) {
|
||||||
|
AssertIsOnIOThread();
|
||||||
|
|
||||||
|
auto privateOrigin = aMetadata.mIsPrivate;
|
||||||
|
if (!privateOrigin) {
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
const auto& origin = aMetadata.mOrigin;
|
||||||
|
return mCipherKeyManagers.LookupOrInsertWith(
|
||||||
|
origin, [] { return new CipherKeyManager("CacheCipherKeyManager"); });
|
||||||
|
}
|
||||||
|
|
||||||
CacheQuotaClient::~CacheQuotaClient() {
|
CacheQuotaClient::~CacheQuotaClient() {
|
||||||
AssertIsOnBackgroundThread();
|
AssertIsOnBackgroundThread();
|
||||||
MOZ_DIAGNOSTIC_ASSERT(sInstance == this);
|
MOZ_DIAGNOSTIC_ASSERT(sInstance == this);
|
||||||
|
|
|
||||||
9
dom/cache/QuotaClientImpl.h
vendored
9
dom/cache/QuotaClientImpl.h
vendored
|
|
@ -7,9 +7,12 @@
|
||||||
#ifndef mozilla_dom_cache_QuotaClientImpl_h
|
#ifndef mozilla_dom_cache_QuotaClientImpl_h
|
||||||
#define mozilla_dom_cache_QuotaClientImpl_h
|
#define mozilla_dom_cache_QuotaClientImpl_h
|
||||||
|
|
||||||
|
#include "CacheCipherKeyManager.h"
|
||||||
|
#include "mozilla/RefPtr.h"
|
||||||
#include "mozilla/dom/QMResult.h"
|
#include "mozilla/dom/QMResult.h"
|
||||||
#include "mozilla/dom/cache/QuotaClient.h"
|
#include "mozilla/dom/cache/QuotaClient.h"
|
||||||
#include "mozilla/dom/cache/FileUtils.h"
|
#include "mozilla/dom/cache/FileUtils.h"
|
||||||
|
#include "mozilla/dom/cache/Types.h"
|
||||||
#include "mozilla/dom/quota/ResultExtensions.h"
|
#include "mozilla/dom/quota/ResultExtensions.h"
|
||||||
|
|
||||||
namespace mozilla::dom::cache {
|
namespace mozilla::dom::cache {
|
||||||
|
|
@ -119,6 +122,9 @@ class CacheQuotaClient final : public quota::Client {
|
||||||
nsresult WipePaddingFileInternal(
|
nsresult WipePaddingFileInternal(
|
||||||
const CacheDirectoryMetadata& aDirectoryMetadata, nsIFile* aBaseDir);
|
const CacheDirectoryMetadata& aDirectoryMetadata, nsIFile* aBaseDir);
|
||||||
|
|
||||||
|
RefPtr<CipherKeyManager> GetOrCreateCipherKeyManager(
|
||||||
|
const quota::PrincipalMetadata& aMetadata);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
~CacheQuotaClient();
|
~CacheQuotaClient();
|
||||||
|
|
||||||
|
|
@ -128,6 +134,9 @@ class CacheQuotaClient final : public quota::Client {
|
||||||
void ForceKillActors() override;
|
void ForceKillActors() override;
|
||||||
void FinalizeShutdown() override;
|
void FinalizeShutdown() override;
|
||||||
|
|
||||||
|
// Should always be accessed from QM IO thread.
|
||||||
|
nsTHashMap<nsCStringHashKey, RefPtr<CipherKeyManager>> mCipherKeyManagers;
|
||||||
|
|
||||||
NS_INLINE_DECL_THREADSAFE_REFCOUNTING(CacheQuotaClient, override)
|
NS_INLINE_DECL_THREADSAFE_REFCOUNTING(CacheQuotaClient, override)
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
||||||
14
dom/cache/Types.h
vendored
14
dom/cache/Types.h
vendored
|
|
@ -10,6 +10,7 @@
|
||||||
#include <functional>
|
#include <functional>
|
||||||
#include <stdint.h>
|
#include <stdint.h>
|
||||||
#include "mozilla/dom/quota/CommonMetadata.h"
|
#include "mozilla/dom/quota/CommonMetadata.h"
|
||||||
|
#include "mozilla/dom/quota/PersistenceType.h"
|
||||||
#include "nsCOMPtr.h"
|
#include "nsCOMPtr.h"
|
||||||
#include "nsIFile.h"
|
#include "nsIFile.h"
|
||||||
#include "nsIInputStream.h"
|
#include "nsIInputStream.h"
|
||||||
|
|
@ -31,17 +32,20 @@ struct CacheDirectoryMetadata : quota::ClientMetadata {
|
||||||
nsCOMPtr<nsIFile> mDir;
|
nsCOMPtr<nsIFile> mDir;
|
||||||
int64_t mDirectoryLockId = -1;
|
int64_t mDirectoryLockId = -1;
|
||||||
|
|
||||||
explicit CacheDirectoryMetadata(quota::PrincipalMetadata aPrincipalMetadata)
|
explicit CacheDirectoryMetadata(
|
||||||
|
const quota::PrincipalMetadata& aPrincipalMetadata)
|
||||||
: quota::ClientMetadata(
|
: quota::ClientMetadata(
|
||||||
quota::OriginMetadata{std::move(aPrincipalMetadata),
|
quota::OriginMetadata{aPrincipalMetadata,
|
||||||
quota::PERSISTENCE_TYPE_DEFAULT},
|
aPrincipalMetadata.mIsPrivate
|
||||||
|
? quota::PERSISTENCE_TYPE_PRIVATE
|
||||||
|
: quota::PERSISTENCE_TYPE_DEFAULT},
|
||||||
quota::Client::Type::DOMCACHE) {}
|
quota::Client::Type::DOMCACHE) {}
|
||||||
|
|
||||||
explicit CacheDirectoryMetadata(quota::OriginMetadata aOriginMetadata)
|
explicit CacheDirectoryMetadata(quota::OriginMetadata aOriginMetadata)
|
||||||
: quota::ClientMetadata(std::move(aOriginMetadata),
|
: quota::ClientMetadata(std::move(aOriginMetadata),
|
||||||
quota::Client::Type::DOMCACHE) {
|
quota::Client::Type::DOMCACHE) {
|
||||||
MOZ_DIAGNOSTIC_ASSERT(aOriginMetadata.mPersistenceType ==
|
MOZ_DIAGNOSTIC_ASSERT(mPersistenceType == quota::PERSISTENCE_TYPE_DEFAULT ||
|
||||||
quota::PERSISTENCE_TYPE_DEFAULT);
|
mPersistenceType == quota::PERSISTENCE_TYPE_PRIVATE);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -11605,6 +11605,10 @@ DatabaseFileManager::DatabaseFileManager(
|
||||||
mOriginMetadata(aOriginMetadata),
|
mOriginMetadata(aOriginMetadata),
|
||||||
mDatabaseName(aDatabaseName),
|
mDatabaseName(aDatabaseName),
|
||||||
mDatabaseID(aDatabaseID),
|
mDatabaseID(aDatabaseID),
|
||||||
|
mCipherKeyManager(
|
||||||
|
aIsInPrivateBrowsingMode
|
||||||
|
? new IndexedDBCipherKeyManager("IndexedDBCipherKeyManager")
|
||||||
|
: nullptr),
|
||||||
mEnforcingQuota(aEnforcingQuota),
|
mEnforcingQuota(aEnforcingQuota),
|
||||||
mIsInPrivateBrowsingMode(aIsInPrivateBrowsingMode) {}
|
mIsInPrivateBrowsingMode(aIsInPrivateBrowsingMode) {}
|
||||||
|
|
||||||
|
|
@ -11963,7 +11967,9 @@ nsresult DatabaseFileManager::SyncDeleteFile(nsIFile& aFile,
|
||||||
}
|
}
|
||||||
|
|
||||||
nsresult DatabaseFileManager::Invalidate() {
|
nsresult DatabaseFileManager::Invalidate() {
|
||||||
mCipherKeyManager.Invalidate();
|
if (mCipherKeyManager) {
|
||||||
|
mCipherKeyManager->Invalidate();
|
||||||
|
}
|
||||||
|
|
||||||
QM_TRY(MOZ_TO_RESULT(FileInfoManager::Invalidate()));
|
QM_TRY(MOZ_TO_RESULT(FileInfoManager::Invalidate()));
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -32,7 +32,7 @@ class DatabaseFileManager final
|
||||||
const nsString mDatabaseName;
|
const nsString mDatabaseName;
|
||||||
const nsCString mDatabaseID;
|
const nsCString mDatabaseID;
|
||||||
|
|
||||||
mutable IndexedDBCipherKeyManager mCipherKeyManager;
|
RefPtr<IndexedDBCipherKeyManager> mCipherKeyManager;
|
||||||
|
|
||||||
LazyInitializedOnce<const nsString> mDirectoryPath;
|
LazyInitializedOnce<const nsString> mDirectoryPath;
|
||||||
LazyInitializedOnce<const nsString> mJournalDirectoryPath;
|
LazyInitializedOnce<const nsString> mJournalDirectoryPath;
|
||||||
|
|
@ -84,7 +84,10 @@ class DatabaseFileManager final
|
||||||
const nsCString& DatabaseID() const { return mDatabaseID; }
|
const nsCString& DatabaseID() const { return mDatabaseID; }
|
||||||
|
|
||||||
IndexedDBCipherKeyManager& MutableCipherKeyManagerRef() const {
|
IndexedDBCipherKeyManager& MutableCipherKeyManagerRef() const {
|
||||||
return mCipherKeyManager;
|
MOZ_ASSERT(mIsInPrivateBrowsingMode);
|
||||||
|
MOZ_ASSERT(mCipherKeyManager);
|
||||||
|
|
||||||
|
return *mCipherKeyManager;
|
||||||
}
|
}
|
||||||
|
|
||||||
auto IsInPrivateBrowsingMode() const { return mIsInPrivateBrowsingMode; }
|
auto IsInPrivateBrowsingMode() const { return mIsInPrivateBrowsingMode; }
|
||||||
|
|
|
||||||
|
|
@ -1,53 +0,0 @@
|
||||||
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
|
||||||
/* vim: set ts=8 sts=2 et sw=2 tw=80: */
|
|
||||||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
|
||||||
* License, v. 2.0. If a copy of the MPL was not distributed with this file,
|
|
||||||
* You can obtain one at http://mozilla.org/MPL/2.0/. */
|
|
||||||
|
|
||||||
#include "IndexedDBCipherKeyManager.h"
|
|
||||||
|
|
||||||
#include "mozilla/dom/quota/QuotaCommon.h"
|
|
||||||
|
|
||||||
namespace mozilla::dom::indexedDB {
|
|
||||||
|
|
||||||
Maybe<CipherKey> IndexedDBCipherKeyManager::Get(const nsACString& aKeyId) {
|
|
||||||
auto lockedCipherKeys = mCipherKeys.Lock();
|
|
||||||
|
|
||||||
MOZ_ASSERT(!mInvalidated);
|
|
||||||
|
|
||||||
return lockedCipherKeys->MaybeGet(aKeyId);
|
|
||||||
}
|
|
||||||
|
|
||||||
CipherKey IndexedDBCipherKeyManager::Ensure(const nsACString& aKeyId) {
|
|
||||||
auto lockedCipherKeys = mCipherKeys.Lock();
|
|
||||||
|
|
||||||
MOZ_ASSERT(!mInvalidated);
|
|
||||||
|
|
||||||
return lockedCipherKeys->LookupOrInsertWith(aKeyId, [] {
|
|
||||||
// Generate a new key if one corresponding to keyStoreId does not exist
|
|
||||||
// already.
|
|
||||||
|
|
||||||
QM_TRY_RETURN(IndexedDBCipherStrategy::GenerateKey(), [](const auto&) {
|
|
||||||
// Bug1800110 Propagate the error to the caller rather than asserting.
|
|
||||||
MOZ_RELEASE_ASSERT(false);
|
|
||||||
|
|
||||||
return CipherKey{};
|
|
||||||
});
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
bool IndexedDBCipherKeyManager::Invalidated() {
|
|
||||||
auto lockedCipherKeys = mCipherKeys.Lock();
|
|
||||||
|
|
||||||
return mInvalidated;
|
|
||||||
}
|
|
||||||
|
|
||||||
void IndexedDBCipherKeyManager::Invalidate() {
|
|
||||||
auto lockedCipherKeys = mCipherKeys.Lock();
|
|
||||||
|
|
||||||
mInvalidated.Flip();
|
|
||||||
|
|
||||||
lockedCipherKeys->Clear();
|
|
||||||
}
|
|
||||||
|
|
||||||
} // namespace mozilla::dom::indexedDB
|
|
||||||
|
|
@ -7,47 +7,25 @@
|
||||||
#ifndef DOM_INDEXEDDB_INDEXEDDBCIPHERKEYMANAGER_H_
|
#ifndef DOM_INDEXEDDB_INDEXEDDBCIPHERKEYMANAGER_H_
|
||||||
#define DOM_INDEXEDDB_INDEXEDDBCIPHERKEYMANAGER_H_
|
#define DOM_INDEXEDDB_INDEXEDDBCIPHERKEYMANAGER_H_
|
||||||
|
|
||||||
#include "FlippedOnce.h"
|
#include "mozilla/dom/quota/CipherKeyManager.h"
|
||||||
#include "mozilla/DataMutex.h"
|
|
||||||
#include "mozilla/dom/quota/IPCStreamCipherStrategy.h"
|
#include "mozilla/dom/quota/IPCStreamCipherStrategy.h"
|
||||||
#include "nsTHashMap.h"
|
|
||||||
|
|
||||||
namespace mozilla::dom::indexedDB {
|
namespace mozilla::dom {
|
||||||
|
|
||||||
using IndexedDBCipherStrategy = quota::IPCStreamCipherStrategy;
|
// IndexedDBCipherKeyManager is used by IndexedDB operations to store/retrieve
|
||||||
|
// keys in private browsing mode. All data in IndexedDB must be encrypted
|
||||||
|
// using a cipher key and unique IV (Initialization Vector). While there's a
|
||||||
|
// separate cipher key for every blob file; the SQLite database gets encrypted
|
||||||
|
// using the commmon database key. All keys pertaining to a single IndexedDB
|
||||||
|
// database get stored together using quota::CipherKeyManager. So, the hashmap
|
||||||
|
// can be used to look up the common database key and blob keys using "default"
|
||||||
|
// and blob file ids respectively.
|
||||||
|
|
||||||
|
using IndexedDBCipherStrategy = mozilla::dom::quota::IPCStreamCipherStrategy;
|
||||||
|
using IndexedDBCipherKeyManager =
|
||||||
|
mozilla::dom::quota::CipherKeyManager<IndexedDBCipherStrategy>;
|
||||||
using CipherKey = IndexedDBCipherStrategy::KeyType;
|
using CipherKey = IndexedDBCipherStrategy::KeyType;
|
||||||
|
|
||||||
class IndexedDBCipherKeyManager {
|
} // namespace mozilla::dom
|
||||||
// This helper class is used by IndexedDB operations to store/retrieve cipher
|
|
||||||
// keys in private browsing mode. All data in IndexedDB must be encrypted
|
|
||||||
// using a cipher key and unique IV (Initialization Vector). While there's a
|
|
||||||
// separate cipher key for every blob file; the SQLite database gets encrypted
|
|
||||||
// using the commmon database key. All keys pertaining to a single IndexedDB
|
|
||||||
// database get stored together in a hashmap. So the hashmap can be used to
|
|
||||||
// to look up the common database key and blob keys using "default" and blob
|
|
||||||
// file ids respectively.
|
|
||||||
|
|
||||||
public:
|
|
||||||
IndexedDBCipherKeyManager() : mCipherKeys("IndexedDBCipherKeyManager"){};
|
|
||||||
|
|
||||||
Maybe<CipherKey> Get(const nsACString& aKeyId = "default"_ns);
|
|
||||||
|
|
||||||
CipherKey Ensure(const nsACString& aKeyId = "default"_ns);
|
|
||||||
|
|
||||||
bool Invalidated();
|
|
||||||
|
|
||||||
// After calling this method, callers should not call any more methods on this
|
|
||||||
// class.
|
|
||||||
void Invalidate();
|
|
||||||
|
|
||||||
private:
|
|
||||||
// XXX Maybe we can avoid a mutex here by moving all accesses to the
|
|
||||||
// background thread.
|
|
||||||
DataMutex<nsTHashMap<nsCStringHashKey, CipherKey>> mCipherKeys;
|
|
||||||
|
|
||||||
FlippedOnce<false> mInvalidated;
|
|
||||||
};
|
|
||||||
|
|
||||||
} // namespace mozilla::dom::indexedDB
|
|
||||||
|
|
||||||
#endif // DOM_INDEXEDDB_INDEXEDDBCIPHERKEYMANAGER_H_
|
#endif // DOM_INDEXEDDB_INDEXEDDBCIPHERKEYMANAGER_H_
|
||||||
|
|
|
||||||
|
|
@ -69,7 +69,6 @@ UNIFIED_SOURCES += [
|
||||||
"IDBTransaction.cpp",
|
"IDBTransaction.cpp",
|
||||||
"IndexedDatabase.cpp",
|
"IndexedDatabase.cpp",
|
||||||
"IndexedDatabaseManager.cpp",
|
"IndexedDatabaseManager.cpp",
|
||||||
"IndexedDBCipherKeyManager.cpp",
|
|
||||||
"IndexedDBCommon.cpp",
|
"IndexedDBCommon.cpp",
|
||||||
"KeyPath.cpp",
|
"KeyPath.cpp",
|
||||||
"ProfilerHelpers.cpp",
|
"ProfilerHelpers.cpp",
|
||||||
|
|
|
||||||
97
dom/quota/CipherKeyManager.h
Normal file
97
dom/quota/CipherKeyManager.h
Normal file
|
|
@ -0,0 +1,97 @@
|
||||||
|
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
||||||
|
/* vim: set ts=8 sts=2 et sw=2 tw=80: */
|
||||||
|
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||||
|
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||||
|
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||||
|
|
||||||
|
#ifndef DOM_QUOTA_CIPHERKEYMANAGER_H_
|
||||||
|
#define DOM_QUOTA_CIPHERKEYMANAGER_H_
|
||||||
|
|
||||||
|
#include "mozilla/DataMutex.h"
|
||||||
|
#include "mozilla/dom/FlippedOnce.h"
|
||||||
|
#include "mozilla/dom/quota/QuotaCommon.h"
|
||||||
|
#include "nsTHashMap.h"
|
||||||
|
|
||||||
|
namespace mozilla::dom::quota {
|
||||||
|
|
||||||
|
using mozilla::FlippedOnce;
|
||||||
|
|
||||||
|
template <typename CipherStrategy>
|
||||||
|
class CipherKeyManager {
|
||||||
|
// This helper class is used by quota clients to store/retrieve cipher
|
||||||
|
// keys in private browsing mode. All data in private mode must be encrypted
|
||||||
|
// using a cipher key and unique IV (Initialization Vector).
|
||||||
|
|
||||||
|
// This class uses hashmap (represented by mCipherKeys) to store cipher keys
|
||||||
|
// and is currently used by IndexedDB and Cache quota clients. At any given
|
||||||
|
// time, IndexedDB may contain multiple instances of this class where each is
|
||||||
|
// used to cipherkeys relevant to a particular database. Unlike IndexedDB,
|
||||||
|
// CacheAPI only has one physical sqlite db per origin, so all cipher keys
|
||||||
|
// corresponding to an origin in cacheAPI gets stored together in this
|
||||||
|
// hashmap.
|
||||||
|
|
||||||
|
// Bug1859558: It could be better if QuotaManager owns cipherKeys for
|
||||||
|
// all the quota clients and exposes, methods like
|
||||||
|
// GetOrCreateCipherManager(aOrigin, aDatabaseName, aClientType) for
|
||||||
|
// clients to access their respective cipherKeys scoped.
|
||||||
|
NS_INLINE_DECL_THREADSAFE_REFCOUNTING(CipherKeyManager)
|
||||||
|
|
||||||
|
using CipherKey = typename CipherStrategy::KeyType;
|
||||||
|
|
||||||
|
public:
|
||||||
|
explicit CipherKeyManager(const char* aName) : mCipherKeys(aName){};
|
||||||
|
|
||||||
|
Maybe<CipherKey> Get(const nsACString& aKeyId = "default"_ns) {
|
||||||
|
auto lockedCipherKeys = mCipherKeys.Lock();
|
||||||
|
|
||||||
|
MOZ_ASSERT(!mInvalidated);
|
||||||
|
|
||||||
|
return lockedCipherKeys->MaybeGet(aKeyId);
|
||||||
|
}
|
||||||
|
|
||||||
|
CipherKey Ensure(const nsACString& aKeyId = "default"_ns) {
|
||||||
|
auto lockedCipherKeys = mCipherKeys.Lock();
|
||||||
|
|
||||||
|
MOZ_ASSERT(!mInvalidated);
|
||||||
|
|
||||||
|
return lockedCipherKeys->LookupOrInsertWith(aKeyId, [] {
|
||||||
|
// Generate a new key if one corresponding to keyStoreId does not exist
|
||||||
|
// already.
|
||||||
|
|
||||||
|
QM_TRY_RETURN(CipherStrategy::GenerateKey(), [](const auto&) {
|
||||||
|
// Bug1800110 Propagate the error to the caller rather than asserting.
|
||||||
|
MOZ_RELEASE_ASSERT(false);
|
||||||
|
|
||||||
|
return CipherKey{};
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
bool Invalidated() {
|
||||||
|
auto lockedCipherKeys = mCipherKeys.Lock();
|
||||||
|
|
||||||
|
return mInvalidated;
|
||||||
|
}
|
||||||
|
|
||||||
|
// After calling this method, callers should not call any more methods on this
|
||||||
|
// class.
|
||||||
|
void Invalidate() {
|
||||||
|
auto lockedCipherKeys = mCipherKeys.Lock();
|
||||||
|
|
||||||
|
mInvalidated.Flip();
|
||||||
|
|
||||||
|
lockedCipherKeys->Clear();
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
~CipherKeyManager() = default;
|
||||||
|
// XXX Maybe we can avoid a mutex here by moving all accesses to the
|
||||||
|
// background thread.
|
||||||
|
DataMutex<nsTHashMap<nsCStringHashKey, CipherKey>> mCipherKeys;
|
||||||
|
|
||||||
|
FlippedOnce<false> mInvalidated;
|
||||||
|
};
|
||||||
|
|
||||||
|
} // namespace mozilla::dom::quota
|
||||||
|
|
||||||
|
#endif // DOM_QUOTA_CIPHERKEYMANAGER_H_
|
||||||
|
|
@ -29,6 +29,7 @@ EXPORTS.mozilla.dom.quota += [
|
||||||
"AssertionsImpl.h",
|
"AssertionsImpl.h",
|
||||||
"CachingDatabaseConnection.h",
|
"CachingDatabaseConnection.h",
|
||||||
"CheckedUnsafePtr.h",
|
"CheckedUnsafePtr.h",
|
||||||
|
"CipherKeyManager.h",
|
||||||
"CipherStrategy.h",
|
"CipherStrategy.h",
|
||||||
"Client.h",
|
"Client.h",
|
||||||
"ClientImpl.h",
|
"ClientImpl.h",
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue