forked from mirrors/gecko-dev
Backed out changeset 737fde266c8d (bug1896920) Backed out changeset 1f466fdca856 (bug1896920) Backed out changeset 0843abab6f3b (bug1896920) Backed out changeset 64ba753ffaef (bug1895750) Backed out changeset cdcb4997f7bc (bug 1892020) Backed out changeset a22c76f82cbd (bug1895750) Backed out changeset 01da838f2fd0 (bug 1892009) Backed out changeset f09f5993b414 (bug 1892015) Backed out changeset da1e40d9d0ca (bug 1892014) Backed out changeset d2be17744b0b (bug 1892013) Backed out changeset 2afba8f5e25b (bug 1892010)
892 lines
31 KiB
C++
892 lines
31 KiB
C++
/* -*- 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 "ErrorList.h"
|
|
#include "IdentityCredentialStorageService.h"
|
|
#include "MainThreadUtils.h"
|
|
#include "mozilla/AppShutdown.h"
|
|
#include "mozilla/Base64.h"
|
|
#include "mozilla/ClearOnShutdown.h"
|
|
#include "mozilla/Components.h"
|
|
#include "mozilla/OriginAttributes.h"
|
|
#include "mozilla/Services.h"
|
|
#include "mozilla/StaticPrefs_dom.h"
|
|
#include "mozilla/StaticPtr.h"
|
|
#include "mozIStorageService.h"
|
|
#include "mozIStorageConnection.h"
|
|
#include "mozIStorageStatement.h"
|
|
#include "mozStorageCID.h"
|
|
#include "nsAppDirectoryServiceDefs.h"
|
|
#include "nsComponentManagerUtils.h"
|
|
#include "nsCRT.h"
|
|
#include "nsDebug.h"
|
|
#include "nsDirectoryServiceUtils.h"
|
|
#include "nsIObserverService.h"
|
|
#include "nsIWritablePropertyBag2.h"
|
|
#include "nsServiceManagerUtils.h"
|
|
#include "nsThreadUtils.h"
|
|
#include "nsVariant.h"
|
|
#include "prtime.h"
|
|
|
|
#define ACCOUNT_STATE_FILENAME "credentialstate.sqlite"_ns
|
|
#define SCHEMA_VERSION 1
|
|
#define MODIFIED_NOW PR_Now()
|
|
|
|
namespace mozilla {
|
|
|
|
StaticRefPtr<IdentityCredentialStorageService>
|
|
gIdentityCredentialStorageService;
|
|
|
|
NS_IMPL_ISUPPORTS(IdentityCredentialStorageService,
|
|
nsIIdentityCredentialStorageService, nsIObserver,
|
|
nsIAsyncShutdownBlocker)
|
|
|
|
already_AddRefed<IdentityCredentialStorageService>
|
|
IdentityCredentialStorageService::GetSingleton() {
|
|
AssertIsOnMainThread();
|
|
MOZ_ASSERT(XRE_IsParentProcess());
|
|
if (!gIdentityCredentialStorageService) {
|
|
gIdentityCredentialStorageService = new IdentityCredentialStorageService();
|
|
ClearOnShutdown(&gIdentityCredentialStorageService);
|
|
nsresult rv = gIdentityCredentialStorageService->Init();
|
|
NS_ENSURE_SUCCESS(rv, nullptr);
|
|
}
|
|
RefPtr<IdentityCredentialStorageService> service =
|
|
gIdentityCredentialStorageService;
|
|
return service.forget();
|
|
}
|
|
|
|
NS_IMETHODIMP IdentityCredentialStorageService::GetName(nsAString& aName) {
|
|
aName = u"IdentityCredentialStorageService: Flushing data"_ns;
|
|
return NS_OK;
|
|
}
|
|
|
|
NS_IMETHODIMP IdentityCredentialStorageService::BlockShutdown(
|
|
nsIAsyncShutdownClient* aClient) {
|
|
MOZ_ASSERT(NS_IsMainThread());
|
|
nsresult rv = WaitForInitialization();
|
|
NS_ENSURE_SUCCESS(rv, rv);
|
|
|
|
MonitorAutoLock lock(mMonitor);
|
|
mShuttingDown.Flip();
|
|
|
|
if (mMemoryDatabaseConnection) {
|
|
Unused << mMemoryDatabaseConnection->Close();
|
|
mMemoryDatabaseConnection = nullptr;
|
|
}
|
|
|
|
RefPtr<IdentityCredentialStorageService> self = this;
|
|
mBackgroundThread->Dispatch(
|
|
NS_NewRunnableFunction(
|
|
"IdentityCredentialStorageService::BlockShutdown",
|
|
[self]() {
|
|
MonitorAutoLock lock(self->mMonitor);
|
|
|
|
MOZ_ASSERT(self->mPendingWrites == 0);
|
|
|
|
if (self->mDiskDatabaseConnection) {
|
|
Unused << self->mDiskDatabaseConnection->Close();
|
|
self->mDiskDatabaseConnection = nullptr;
|
|
}
|
|
|
|
self->mFinalized.Flip();
|
|
self->mMonitor.NotifyAll();
|
|
NS_DispatchToMainThread(NS_NewRunnableFunction(
|
|
"IdentityCredentialStorageService::BlockShutdown "
|
|
"- mainthread callback",
|
|
[self]() { self->Finalize(); }));
|
|
}),
|
|
NS_DISPATCH_EVENT_MAY_BLOCK);
|
|
|
|
return NS_OK;
|
|
}
|
|
|
|
NS_IMETHODIMP
|
|
IdentityCredentialStorageService::GetState(nsIPropertyBag** aBagOut) {
|
|
return NS_OK;
|
|
}
|
|
|
|
already_AddRefed<nsIAsyncShutdownClient>
|
|
IdentityCredentialStorageService::GetAsyncShutdownBarrier() const {
|
|
nsresult rv;
|
|
nsCOMPtr<nsIAsyncShutdownService> svc = components::AsyncShutdown::Service();
|
|
MOZ_RELEASE_ASSERT(svc);
|
|
|
|
nsCOMPtr<nsIAsyncShutdownClient> client;
|
|
rv = svc->GetProfileBeforeChange(getter_AddRefs(client));
|
|
MOZ_RELEASE_ASSERT(NS_SUCCEEDED(rv));
|
|
MOZ_RELEASE_ASSERT(client);
|
|
return client.forget();
|
|
}
|
|
|
|
nsresult IdentityCredentialStorageService::Init() {
|
|
AssertIsOnMainThread();
|
|
|
|
nsCOMPtr<nsIAsyncShutdownClient> asc = GetAsyncShutdownBarrier();
|
|
if (!asc) {
|
|
return NS_ERROR_NOT_AVAILABLE;
|
|
}
|
|
|
|
// We should only allow this service to start before its
|
|
// shutdown barrier is closed, so it never leaks.
|
|
bool closed;
|
|
nsresult rv = asc->GetIsClosed(&closed);
|
|
if (closed || NS_WARN_IF(NS_FAILED(rv))) {
|
|
MonitorAutoLock lock(mMonitor);
|
|
mShuttingDown.Flip();
|
|
return NS_ERROR_ILLEGAL_DURING_SHUTDOWN;
|
|
}
|
|
|
|
rv = asc->AddBlocker(this, NS_LITERAL_STRING_FROM_CSTRING(__FILE__), __LINE__,
|
|
u""_ns);
|
|
NS_ENSURE_SUCCESS(rv, rv);
|
|
|
|
rv = NS_GetSpecialDirectory(NS_APP_USER_PROFILE_50_DIR,
|
|
getter_AddRefs(mDatabaseFile));
|
|
NS_ENSURE_SUCCESS(rv, rv);
|
|
rv = mDatabaseFile->AppendNative(ACCOUNT_STATE_FILENAME);
|
|
NS_ENSURE_SUCCESS(rv, rv);
|
|
|
|
// Register the PBMode cleaner (IdentityCredentialStorageService::Observe) as
|
|
// an observer.
|
|
nsCOMPtr<nsIObserverService> observerService =
|
|
mozilla::services::GetObserverService();
|
|
NS_ENSURE_TRUE(observerService, NS_ERROR_FAILURE);
|
|
observerService->AddObserver(this, "last-pb-context-exited", false);
|
|
|
|
rv = GetMemoryDatabaseConnection();
|
|
if (NS_WARN_IF(NS_FAILED(rv))) {
|
|
MonitorAutoLock lock(mMonitor);
|
|
mErrored.Flip();
|
|
return rv;
|
|
}
|
|
|
|
NS_ENSURE_SUCCESS(
|
|
NS_CreateBackgroundTaskQueue("IdentityCredentialStorage",
|
|
getter_AddRefs(mBackgroundThread)),
|
|
NS_ERROR_FAILURE);
|
|
|
|
RefPtr<IdentityCredentialStorageService> self = this;
|
|
|
|
mBackgroundThread->Dispatch(
|
|
NS_NewRunnableFunction("IdentityCredentialStorageService::Init",
|
|
[self]() {
|
|
MonitorAutoLock lock(self->mMonitor);
|
|
nsresult rv = self->GetDiskDatabaseConnection();
|
|
if (NS_WARN_IF(NS_FAILED(rv))) {
|
|
self->mErrored.Flip();
|
|
self->mMonitor.Notify();
|
|
return;
|
|
}
|
|
|
|
rv = self->LoadMemoryTableFromDisk();
|
|
if (NS_WARN_IF(NS_FAILED(rv))) {
|
|
self->mErrored.Flip();
|
|
self->mMonitor.Notify();
|
|
return;
|
|
}
|
|
|
|
self->mInitialized.Flip();
|
|
self->mMonitor.Notify();
|
|
}),
|
|
NS_DISPATCH_EVENT_MAY_BLOCK);
|
|
|
|
return NS_OK;
|
|
}
|
|
|
|
nsresult IdentityCredentialStorageService::WaitForInitialization() {
|
|
MOZ_ASSERT(NS_IsMainThread(),
|
|
"Must only wait for initialization in the main thread.");
|
|
MonitorAutoLock lock(mMonitor);
|
|
while (!mInitialized && !mErrored && !mShuttingDown) {
|
|
mMonitor.Wait();
|
|
}
|
|
if (mErrored) {
|
|
return NS_ERROR_FAILURE;
|
|
}
|
|
if (mShuttingDown) {
|
|
return NS_ERROR_NOT_AVAILABLE;
|
|
}
|
|
return NS_OK;
|
|
}
|
|
|
|
void IdentityCredentialStorageService::Finalize() {
|
|
nsCOMPtr<nsIAsyncShutdownClient> asc = GetAsyncShutdownBarrier();
|
|
MOZ_ASSERT(asc);
|
|
DebugOnly<nsresult> rv = asc->RemoveBlocker(this);
|
|
MOZ_ASSERT(NS_SUCCEEDED(rv));
|
|
}
|
|
|
|
// static
|
|
nsresult IdentityCredentialStorageService::ValidatePrincipal(
|
|
nsIPrincipal* aPrincipal) {
|
|
// We add some constraints on the RP principal where it is provided to reduce
|
|
// edge cases in implementation. These are reasonable constraints with the
|
|
// semantics of the store: it must be a http or https content principal.
|
|
NS_ENSURE_ARG_POINTER(aPrincipal);
|
|
NS_ENSURE_TRUE(aPrincipal->GetIsContentPrincipal(), NS_ERROR_FAILURE);
|
|
nsCString scheme;
|
|
nsresult rv = aPrincipal->GetScheme(scheme);
|
|
NS_ENSURE_SUCCESS(rv, rv);
|
|
NS_ENSURE_TRUE(scheme.Equals("http"_ns) || scheme.Equals("https"_ns),
|
|
NS_ERROR_FAILURE);
|
|
return NS_OK;
|
|
}
|
|
|
|
nsresult IdentityCredentialStorageService::GetMemoryDatabaseConnection() {
|
|
return IdentityCredentialStorageService::GetDatabaseConnectionInternal(
|
|
getter_AddRefs(mMemoryDatabaseConnection), nullptr);
|
|
}
|
|
|
|
nsresult IdentityCredentialStorageService::GetDiskDatabaseConnection() {
|
|
NS_ENSURE_TRUE(mDatabaseFile, NS_ERROR_NULL_POINTER);
|
|
return IdentityCredentialStorageService::GetDatabaseConnectionInternal(
|
|
getter_AddRefs(mDiskDatabaseConnection), mDatabaseFile);
|
|
}
|
|
|
|
// static
|
|
nsresult IdentityCredentialStorageService::GetDatabaseConnectionInternal(
|
|
mozIStorageConnection** aDatabase, nsIFile* aFile) {
|
|
NS_ENSURE_TRUE(aDatabase, NS_ERROR_UNEXPECTED);
|
|
NS_ENSURE_STATE(!(*aDatabase));
|
|
nsCOMPtr<mozIStorageService> storage =
|
|
do_GetService(MOZ_STORAGE_SERVICE_CONTRACTID);
|
|
NS_ENSURE_TRUE(storage, NS_ERROR_UNEXPECTED);
|
|
nsresult rv;
|
|
|
|
if (aFile) {
|
|
rv = storage->OpenDatabase(aFile, mozIStorageService::CONNECTION_DEFAULT,
|
|
aDatabase);
|
|
if (rv == NS_ERROR_FILE_CORRUPTED) {
|
|
rv = aFile->Remove(false);
|
|
NS_ENSURE_SUCCESS(rv, rv);
|
|
rv = storage->OpenDatabase(aFile, mozIStorageService::CONNECTION_DEFAULT,
|
|
aDatabase);
|
|
}
|
|
NS_ENSURE_SUCCESS(rv, rv);
|
|
} else {
|
|
rv = storage->OpenSpecialDatabase(
|
|
kMozStorageMemoryStorageKey, "icsprivatedb"_ns,
|
|
mozIStorageService::CONNECTION_DEFAULT, aDatabase);
|
|
NS_ENSURE_SUCCESS(rv, rv);
|
|
}
|
|
|
|
NS_ENSURE_TRUE(*aDatabase, NS_ERROR_UNEXPECTED);
|
|
bool ready = false;
|
|
(*aDatabase)->GetConnectionReady(&ready);
|
|
NS_ENSURE_TRUE(ready, NS_ERROR_UNEXPECTED);
|
|
rv = EnsureTable(*aDatabase);
|
|
NS_ENSURE_SUCCESS(rv, rv);
|
|
return NS_OK;
|
|
}
|
|
|
|
// static
|
|
nsresult IdentityCredentialStorageService::EnsureTable(
|
|
mozIStorageConnection* aDatabase) {
|
|
NS_ENSURE_ARG_POINTER(aDatabase);
|
|
bool tableExists = false;
|
|
aDatabase->TableExists("identity"_ns, &tableExists);
|
|
if (!tableExists) {
|
|
// Currently there is only one schema version, so we just need to create the
|
|
// table. The definition uses no explicit rowid column, instead primary
|
|
// keying on the tuple defined in the spec. We store two bits and some
|
|
// additional data to make integration with the ClearDataService
|
|
// easier/possible.
|
|
nsresult rv = aDatabase->SetSchemaVersion(SCHEMA_VERSION);
|
|
NS_ENSURE_SUCCESS(rv, rv);
|
|
rv = aDatabase->ExecuteSimpleSQL(
|
|
"CREATE TABLE identity ("
|
|
"rpOrigin TEXT NOT NULL"
|
|
",idpOrigin TEXT NOT NULL"
|
|
",credentialId TEXT NOT NULL"
|
|
",registered INTEGER"
|
|
",allowLogout INTEGER"
|
|
",modificationTime INTEGER"
|
|
",rpBaseDomain TEXT"
|
|
",PRIMARY KEY (rpOrigin, idpOrigin, credentialId)"
|
|
")"_ns);
|
|
NS_ENSURE_SUCCESS(rv, rv);
|
|
}
|
|
return NS_OK;
|
|
}
|
|
|
|
nsresult IdentityCredentialStorageService::LoadMemoryTableFromDisk() {
|
|
MOZ_ASSERT(!NS_IsMainThread(),
|
|
"Must not load the table from disk in the main thread.");
|
|
auto constexpr selectAllQuery =
|
|
"SELECT rpOrigin, idpOrigin, credentialId, registered, allowLogout, "
|
|
"modificationTime, rpBaseDomain FROM identity;"_ns;
|
|
auto constexpr insertQuery =
|
|
"INSERT INTO identity(rpOrigin, idpOrigin, credentialId, registered, "
|
|
"allowLogout, modificationTime, rpBaseDomain) VALUES (?1, ?2, ?3, ?4, "
|
|
"?5, ?6, ?7);"_ns;
|
|
|
|
nsCOMPtr<mozIStorageStatement> writeStmt;
|
|
nsresult rv = mMemoryDatabaseConnection->CreateStatement(
|
|
insertQuery, getter_AddRefs(writeStmt));
|
|
NS_ENSURE_SUCCESS(rv, rv);
|
|
|
|
nsCOMPtr<mozIStorageStatement> readStmt;
|
|
rv = mDiskDatabaseConnection->CreateStatement(selectAllQuery,
|
|
getter_AddRefs(readStmt));
|
|
NS_ENSURE_SUCCESS(rv, rv);
|
|
|
|
bool hasResult;
|
|
while (NS_SUCCEEDED(readStmt->ExecuteStep(&hasResult)) && hasResult) {
|
|
int64_t registered, allowLogout, modificationTime;
|
|
nsCString rpOrigin, idpOrigin, credentialID, rpBaseDomain;
|
|
|
|
// Read values from disk query
|
|
rv = readStmt->GetUTF8String(0, rpOrigin);
|
|
NS_ENSURE_SUCCESS(rv, rv);
|
|
rv = readStmt->GetUTF8String(1, idpOrigin);
|
|
NS_ENSURE_SUCCESS(rv, rv);
|
|
rv = readStmt->GetUTF8String(2, credentialID);
|
|
NS_ENSURE_SUCCESS(rv, rv);
|
|
rv = readStmt->GetInt64(3, ®istered);
|
|
NS_ENSURE_SUCCESS(rv, rv);
|
|
rv = readStmt->GetInt64(4, &allowLogout);
|
|
NS_ENSURE_SUCCESS(rv, rv);
|
|
rv = readStmt->GetInt64(5, &modificationTime);
|
|
NS_ENSURE_SUCCESS(rv, rv);
|
|
rv = readStmt->GetUTF8String(6, rpBaseDomain);
|
|
NS_ENSURE_SUCCESS(rv, rv);
|
|
|
|
// Write values to memory database
|
|
rv = writeStmt->BindUTF8StringByIndex(0, rpOrigin);
|
|
NS_ENSURE_SUCCESS(rv, rv);
|
|
rv = writeStmt->BindUTF8StringByIndex(1, idpOrigin);
|
|
NS_ENSURE_SUCCESS(rv, rv);
|
|
rv = writeStmt->BindUTF8StringByIndex(2, credentialID);
|
|
NS_ENSURE_SUCCESS(rv, rv);
|
|
rv = writeStmt->BindInt64ByIndex(3, registered);
|
|
NS_ENSURE_SUCCESS(rv, rv);
|
|
rv = writeStmt->BindInt64ByIndex(4, allowLogout);
|
|
NS_ENSURE_SUCCESS(rv, rv);
|
|
rv = writeStmt->BindInt64ByIndex(5, modificationTime);
|
|
NS_ENSURE_SUCCESS(rv, rv);
|
|
rv = writeStmt->BindUTF8StringByIndex(6, rpBaseDomain);
|
|
NS_ENSURE_SUCCESS(rv, rv);
|
|
rv = writeStmt->Execute();
|
|
NS_ENSURE_SUCCESS(rv, rv);
|
|
}
|
|
return NS_OK;
|
|
}
|
|
|
|
void IdentityCredentialStorageService::IncrementPendingWrites() {
|
|
MonitorAutoLock lock(mMonitor);
|
|
MOZ_ASSERT(mPendingWrites < std::numeric_limits<uint32_t>::max());
|
|
mPendingWrites++;
|
|
}
|
|
|
|
void IdentityCredentialStorageService::DecrementPendingWrites() {
|
|
MonitorAutoLock lock(mMonitor);
|
|
MOZ_ASSERT(mPendingWrites > 0);
|
|
mPendingWrites--;
|
|
}
|
|
|
|
// static
|
|
nsresult IdentityCredentialStorageService::UpsertData(
|
|
mozIStorageConnection* aDatabaseConnection, nsIPrincipal* aRPPrincipal,
|
|
nsIPrincipal* aIDPPrincipal, nsACString const& aCredentialID,
|
|
bool aRegistered, bool aAllowLogout) {
|
|
NS_ENSURE_ARG_POINTER(aDatabaseConnection);
|
|
NS_ENSURE_ARG_POINTER(aRPPrincipal);
|
|
NS_ENSURE_ARG_POINTER(aIDPPrincipal);
|
|
nsresult rv;
|
|
constexpr auto upsert_query =
|
|
"INSERT INTO identity(rpOrigin, idpOrigin, credentialId, "
|
|
"registered, allowLogout, modificationTime, rpBaseDomain)"
|
|
"VALUES (?1, ?2, ?3, ?4, ?5, ?6, ?7)"
|
|
"ON CONFLICT(rpOrigin, idpOrigin, credentialId)"
|
|
"DO UPDATE SET registered=excluded.registered, "
|
|
"allowLogout=excluded.allowLogout, "
|
|
"modificationTime=excluded.modificationTime"_ns;
|
|
|
|
nsCOMPtr<mozIStorageStatement> stmt;
|
|
rv = aDatabaseConnection->CreateStatement(upsert_query, getter_AddRefs(stmt));
|
|
NS_ENSURE_SUCCESS(rv, rv);
|
|
nsCString rpOrigin;
|
|
rv = aRPPrincipal->GetOrigin(rpOrigin);
|
|
NS_ENSURE_SUCCESS(rv, rv);
|
|
nsCString idpOrigin;
|
|
rv = aIDPPrincipal->GetOrigin(idpOrigin);
|
|
NS_ENSURE_SUCCESS(rv, rv);
|
|
nsCString rpBaseDomain;
|
|
rv = aRPPrincipal->GetBaseDomain(rpBaseDomain);
|
|
NS_ENSURE_SUCCESS(rv, rv);
|
|
rv = stmt->BindUTF8StringByIndex(0, rpOrigin);
|
|
NS_ENSURE_SUCCESS(rv, rv);
|
|
rv = stmt->BindUTF8StringByIndex(1, idpOrigin);
|
|
NS_ENSURE_SUCCESS(rv, rv);
|
|
rv = stmt->BindUTF8StringByIndex(2, aCredentialID);
|
|
NS_ENSURE_SUCCESS(rv, rv);
|
|
rv = stmt->BindInt64ByIndex(3, aRegistered ? 1 : 0);
|
|
NS_ENSURE_SUCCESS(rv, rv);
|
|
rv = stmt->BindInt64ByIndex(4, aAllowLogout ? 1 : 0);
|
|
NS_ENSURE_SUCCESS(rv, rv);
|
|
rv = stmt->BindInt64ByIndex(5, MODIFIED_NOW);
|
|
NS_ENSURE_SUCCESS(rv, rv);
|
|
rv = stmt->BindUTF8StringByIndex(6, rpBaseDomain);
|
|
NS_ENSURE_SUCCESS(rv, rv);
|
|
rv = stmt->Execute();
|
|
NS_ENSURE_SUCCESS(rv, rv);
|
|
return NS_OK;
|
|
}
|
|
|
|
// static
|
|
nsresult IdentityCredentialStorageService::DeleteData(
|
|
mozIStorageConnection* aDatabaseConnection, nsIPrincipal* aRPPrincipal,
|
|
nsIPrincipal* aIDPPrincipal, nsACString const& aCredentialID) {
|
|
NS_ENSURE_ARG_POINTER(aDatabaseConnection);
|
|
NS_ENSURE_ARG_POINTER(aRPPrincipal);
|
|
NS_ENSURE_ARG_POINTER(aIDPPrincipal);
|
|
auto constexpr deleteQuery =
|
|
"DELETE FROM identity WHERE rpOrigin=?1 AND idpOrigin=?2 AND "
|
|
"credentialId=?3"_ns;
|
|
nsCOMPtr<mozIStorageStatement> stmt;
|
|
nsresult rv =
|
|
aDatabaseConnection->CreateStatement(deleteQuery, getter_AddRefs(stmt));
|
|
NS_ENSURE_SUCCESS(rv, rv);
|
|
nsCString rpOrigin;
|
|
rv = aRPPrincipal->GetOrigin(rpOrigin);
|
|
NS_ENSURE_SUCCESS(rv, rv);
|
|
nsCString idpOrigin;
|
|
rv = aIDPPrincipal->GetOrigin(idpOrigin);
|
|
NS_ENSURE_SUCCESS(rv, rv);
|
|
rv = stmt->BindUTF8StringByIndex(0, rpOrigin);
|
|
NS_ENSURE_SUCCESS(rv, rv);
|
|
rv = stmt->BindUTF8StringByIndex(1, idpOrigin);
|
|
NS_ENSURE_SUCCESS(rv, rv);
|
|
rv = stmt->BindUTF8StringByIndex(2, aCredentialID);
|
|
NS_ENSURE_SUCCESS(rv, rv);
|
|
rv = stmt->Execute();
|
|
NS_ENSURE_SUCCESS(rv, rv);
|
|
return NS_OK;
|
|
}
|
|
|
|
// static
|
|
nsresult IdentityCredentialStorageService::ClearData(
|
|
mozIStorageConnection* aDatabaseConnection) {
|
|
NS_ENSURE_ARG_POINTER(aDatabaseConnection);
|
|
nsresult rv =
|
|
aDatabaseConnection->ExecuteSimpleSQL("DELETE FROM identity;"_ns);
|
|
NS_ENSURE_SUCCESS(rv, rv);
|
|
return NS_OK;
|
|
}
|
|
|
|
// static
|
|
nsresult
|
|
IdentityCredentialStorageService::DeleteDataFromOriginAttributesPattern(
|
|
mozIStorageConnection* aDatabaseConnection,
|
|
OriginAttributesPattern const& aOriginAttributesPattern) {
|
|
NS_ENSURE_ARG_POINTER(aDatabaseConnection);
|
|
nsCOMPtr<mozIStorageFunction> patternMatchFunction(
|
|
new OriginAttrsPatternMatchOriginSQLFunction(aOriginAttributesPattern));
|
|
|
|
nsresult rv = aDatabaseConnection->CreateFunction(
|
|
"ORIGIN_ATTRS_PATTERN_MATCH_ORIGIN"_ns, 1, patternMatchFunction);
|
|
NS_ENSURE_SUCCESS(rv, rv);
|
|
|
|
rv = aDatabaseConnection->ExecuteSimpleSQL(
|
|
"DELETE FROM identity WHERE "
|
|
"ORIGIN_ATTRS_PATTERN_MATCH_ORIGIN(rpOrigin);"_ns);
|
|
NS_ENSURE_SUCCESS(rv, rv);
|
|
|
|
rv = aDatabaseConnection->RemoveFunction(
|
|
"ORIGIN_ATTRS_PATTERN_MATCH_ORIGIN"_ns);
|
|
NS_ENSURE_SUCCESS(rv, rv);
|
|
|
|
return NS_OK;
|
|
}
|
|
|
|
// static
|
|
nsresult IdentityCredentialStorageService::DeleteDataFromTimeRange(
|
|
mozIStorageConnection* aDatabaseConnection, int64_t aStart, int64_t aEnd) {
|
|
NS_ENSURE_ARG_POINTER(aDatabaseConnection);
|
|
auto constexpr deleteTimeQuery =
|
|
"DELETE FROM identity WHERE modificationTime > ?1 and modificationTime "
|
|
"< ?2"_ns;
|
|
nsCOMPtr<mozIStorageStatement> stmt;
|
|
nsresult rv = aDatabaseConnection->CreateStatement(deleteTimeQuery,
|
|
getter_AddRefs(stmt));
|
|
NS_ENSURE_SUCCESS(rv, rv);
|
|
rv = stmt->BindInt64ByIndex(0, aStart);
|
|
NS_ENSURE_SUCCESS(rv, rv);
|
|
rv = stmt->BindInt64ByIndex(1, aEnd);
|
|
NS_ENSURE_SUCCESS(rv, rv);
|
|
rv = stmt->Execute();
|
|
NS_ENSURE_SUCCESS(rv, rv);
|
|
return NS_OK;
|
|
}
|
|
|
|
// static
|
|
nsresult IdentityCredentialStorageService::DeleteDataFromPrincipal(
|
|
mozIStorageConnection* aDatabaseConnection, nsIPrincipal* aPrincipal) {
|
|
NS_ENSURE_ARG_POINTER(aDatabaseConnection);
|
|
NS_ENSURE_ARG_POINTER(aPrincipal);
|
|
|
|
nsCString rpOrigin;
|
|
nsresult rv = aPrincipal->GetOrigin(rpOrigin);
|
|
NS_ENSURE_SUCCESS(rv, rv);
|
|
auto constexpr deletePrincipalQuery =
|
|
"DELETE FROM identity WHERE rpOrigin=?1"_ns;
|
|
nsCOMPtr<mozIStorageStatement> stmt;
|
|
rv = aDatabaseConnection->CreateStatement(deletePrincipalQuery,
|
|
getter_AddRefs(stmt));
|
|
NS_ENSURE_SUCCESS(rv, rv);
|
|
rv = stmt->BindUTF8StringByIndex(0, rpOrigin);
|
|
NS_ENSURE_SUCCESS(rv, rv);
|
|
rv = stmt->Execute();
|
|
NS_ENSURE_SUCCESS(rv, rv);
|
|
return NS_OK;
|
|
}
|
|
|
|
// static
|
|
nsresult IdentityCredentialStorageService::DeleteDataFromBaseDomain(
|
|
mozIStorageConnection* aDatabaseConnection, nsACString const& aBaseDomain) {
|
|
NS_ENSURE_ARG_POINTER(aDatabaseConnection);
|
|
|
|
auto constexpr deleteBaseDomainQuery =
|
|
"DELETE FROM identity WHERE rpBaseDomain=?1"_ns;
|
|
nsCOMPtr<mozIStorageStatement> stmt;
|
|
nsresult rv = aDatabaseConnection->CreateStatement(deleteBaseDomainQuery,
|
|
getter_AddRefs(stmt));
|
|
NS_ENSURE_SUCCESS(rv, rv);
|
|
rv = stmt->BindUTF8StringByIndex(0, aBaseDomain);
|
|
NS_ENSURE_SUCCESS(rv, rv);
|
|
rv = stmt->Execute();
|
|
NS_ENSURE_SUCCESS(rv, rv);
|
|
return NS_OK;
|
|
}
|
|
|
|
NS_IMETHODIMP IdentityCredentialStorageService::SetState(
|
|
nsIPrincipal* aRPPrincipal, nsIPrincipal* aIDPPrincipal,
|
|
nsACString const& aCredentialID, bool aRegistered, bool aAllowLogout) {
|
|
AssertIsOnMainThread();
|
|
NS_ENSURE_ARG_POINTER(aRPPrincipal);
|
|
NS_ENSURE_ARG_POINTER(aIDPPrincipal);
|
|
|
|
nsresult rv;
|
|
rv = WaitForInitialization();
|
|
NS_ENSURE_SUCCESS(rv, rv);
|
|
rv = IdentityCredentialStorageService::ValidatePrincipal(aRPPrincipal);
|
|
NS_ENSURE_SUCCESS(rv, rv);
|
|
|
|
rv = UpsertData(mMemoryDatabaseConnection, aRPPrincipal, aIDPPrincipal,
|
|
aCredentialID, aRegistered, aAllowLogout);
|
|
NS_ENSURE_SUCCESS(rv, rv);
|
|
|
|
IncrementPendingWrites();
|
|
RefPtr<IdentityCredentialStorageService> self = this;
|
|
RefPtr<nsIPrincipal> rpPrincipal = aRPPrincipal;
|
|
RefPtr<nsIPrincipal> idpPrincipal = aIDPPrincipal;
|
|
nsCString credentialID(aCredentialID);
|
|
mBackgroundThread->Dispatch(
|
|
NS_NewRunnableFunction("IdentityCredentialStorageService::Init",
|
|
[self, rpPrincipal, idpPrincipal, credentialID,
|
|
aRegistered, aAllowLogout]() {
|
|
nsresult rv = UpsertData(
|
|
self->mDiskDatabaseConnection, rpPrincipal,
|
|
idpPrincipal, credentialID, aRegistered,
|
|
aAllowLogout);
|
|
NS_ENSURE_SUCCESS_VOID(rv);
|
|
self->DecrementPendingWrites();
|
|
}),
|
|
NS_DISPATCH_EVENT_MAY_BLOCK);
|
|
return NS_OK;
|
|
}
|
|
|
|
NS_IMETHODIMP IdentityCredentialStorageService::GetState(
|
|
nsIPrincipal* aRPPrincipal, nsIPrincipal* aIDPPrincipal,
|
|
nsACString const& aCredentialID, bool* aRegistered, bool* aAllowLogout) {
|
|
AssertIsOnMainThread();
|
|
NS_ENSURE_ARG_POINTER(aRPPrincipal);
|
|
NS_ENSURE_ARG_POINTER(aIDPPrincipal);
|
|
|
|
nsresult rv;
|
|
rv = WaitForInitialization();
|
|
NS_ENSURE_SUCCESS(rv, rv);
|
|
rv = IdentityCredentialStorageService::ValidatePrincipal(aRPPrincipal);
|
|
NS_ENSURE_SUCCESS(rv, rv);
|
|
|
|
auto constexpr selectQuery =
|
|
"SELECT registered, allowLogout FROM identity WHERE rpOrigin=?1 AND "
|
|
"idpOrigin=?2 AND credentialId=?3"_ns;
|
|
nsCOMPtr<mozIStorageStatement> stmt;
|
|
rv = mMemoryDatabaseConnection->CreateStatement(selectQuery,
|
|
getter_AddRefs(stmt));
|
|
NS_ENSURE_SUCCESS(rv, rv);
|
|
|
|
nsCString rpOrigin;
|
|
nsCString idpOrigin;
|
|
rv = aRPPrincipal->GetOrigin(rpOrigin);
|
|
NS_ENSURE_SUCCESS(rv, rv);
|
|
rv = aIDPPrincipal->GetOrigin(idpOrigin);
|
|
NS_ENSURE_SUCCESS(rv, rv);
|
|
|
|
rv = stmt->BindUTF8StringByIndex(0, rpOrigin);
|
|
NS_ENSURE_SUCCESS(rv, rv);
|
|
rv = stmt->BindUTF8StringByIndex(1, idpOrigin);
|
|
NS_ENSURE_SUCCESS(rv, rv);
|
|
rv = stmt->BindUTF8StringByIndex(2, aCredentialID);
|
|
NS_ENSURE_SUCCESS(rv, rv);
|
|
|
|
bool hasResult;
|
|
// If we find a result, return it
|
|
if (NS_SUCCEEDED(stmt->ExecuteStep(&hasResult)) && hasResult) {
|
|
int64_t registeredInt, allowLogoutInt;
|
|
rv = stmt->GetInt64(0, ®isteredInt);
|
|
NS_ENSURE_SUCCESS(rv, rv);
|
|
rv = stmt->GetInt64(1, &allowLogoutInt);
|
|
NS_ENSURE_SUCCESS(rv, rv);
|
|
*aRegistered = registeredInt != 0;
|
|
*aAllowLogout = allowLogoutInt != 0;
|
|
return NS_OK;
|
|
}
|
|
|
|
// The tuple was not found on disk or in memory, use the defaults.
|
|
*aRegistered = false;
|
|
*aAllowLogout = false;
|
|
return NS_OK;
|
|
}
|
|
|
|
NS_IMETHODIMP IdentityCredentialStorageService::Delete(
|
|
nsIPrincipal* aRPPrincipal, nsIPrincipal* aIDPPrincipal,
|
|
nsACString const& aCredentialID) {
|
|
AssertIsOnMainThread();
|
|
NS_ENSURE_ARG_POINTER(aRPPrincipal);
|
|
NS_ENSURE_ARG_POINTER(aIDPPrincipal);
|
|
|
|
nsresult rv;
|
|
rv = WaitForInitialization();
|
|
NS_ENSURE_SUCCESS(rv, rv);
|
|
rv = IdentityCredentialStorageService::ValidatePrincipal(aRPPrincipal);
|
|
NS_ENSURE_SUCCESS(rv, rv);
|
|
|
|
rv = DeleteData(mMemoryDatabaseConnection, aRPPrincipal, aIDPPrincipal,
|
|
aCredentialID);
|
|
NS_ENSURE_SUCCESS(rv, rv);
|
|
|
|
IncrementPendingWrites();
|
|
RefPtr<IdentityCredentialStorageService> self = this;
|
|
RefPtr<nsIPrincipal> rpPrincipal = aRPPrincipal;
|
|
RefPtr<nsIPrincipal> idpPrincipal = aIDPPrincipal;
|
|
nsCString credentialID(aCredentialID);
|
|
mBackgroundThread->Dispatch(
|
|
NS_NewRunnableFunction("IdentityCredentialStorageService::Init",
|
|
[self, rpPrincipal, idpPrincipal, credentialID]() {
|
|
nsresult rv = DeleteData(
|
|
self->mDiskDatabaseConnection, rpPrincipal,
|
|
idpPrincipal, credentialID);
|
|
NS_ENSURE_SUCCESS_VOID(rv);
|
|
self->DecrementPendingWrites();
|
|
}),
|
|
NS_DISPATCH_EVENT_MAY_BLOCK);
|
|
|
|
return NS_OK;
|
|
}
|
|
|
|
NS_IMETHODIMP IdentityCredentialStorageService::Clear() {
|
|
AssertIsOnMainThread();
|
|
nsresult rv;
|
|
rv = WaitForInitialization();
|
|
NS_ENSURE_SUCCESS(rv, rv);
|
|
rv = ClearData(mMemoryDatabaseConnection);
|
|
NS_ENSURE_SUCCESS(rv, rv);
|
|
IncrementPendingWrites();
|
|
RefPtr<IdentityCredentialStorageService> self = this;
|
|
mBackgroundThread->Dispatch(
|
|
NS_NewRunnableFunction("IdentityCredentialStorageService::Init",
|
|
[self]() {
|
|
nsresult rv =
|
|
ClearData(self->mDiskDatabaseConnection);
|
|
NS_ENSURE_SUCCESS_VOID(rv);
|
|
self->DecrementPendingWrites();
|
|
}),
|
|
NS_DISPATCH_EVENT_MAY_BLOCK);
|
|
|
|
return NS_OK;
|
|
}
|
|
|
|
NS_IMETHODIMP
|
|
IdentityCredentialStorageService::DeleteFromOriginAttributesPattern(
|
|
nsAString const& aOriginAttributesPattern) {
|
|
AssertIsOnMainThread();
|
|
NS_ENSURE_FALSE(aOriginAttributesPattern.IsEmpty(), NS_ERROR_FAILURE);
|
|
OriginAttributesPattern oaPattern;
|
|
if (!oaPattern.Init(aOriginAttributesPattern)) {
|
|
NS_ERROR("Could not parse the argument for OriginAttributes");
|
|
return NS_ERROR_FAILURE;
|
|
}
|
|
nsresult rv;
|
|
rv = WaitForInitialization();
|
|
NS_ENSURE_SUCCESS(rv, rv);
|
|
rv = DeleteDataFromOriginAttributesPattern(mMemoryDatabaseConnection,
|
|
oaPattern);
|
|
NS_ENSURE_SUCCESS(rv, rv);
|
|
IncrementPendingWrites();
|
|
RefPtr<IdentityCredentialStorageService> self = this;
|
|
mBackgroundThread->Dispatch(
|
|
NS_NewRunnableFunction(
|
|
"IdentityCredentialStorageService::Init",
|
|
[self, oaPattern]() {
|
|
nsresult rv = DeleteDataFromOriginAttributesPattern(
|
|
self->mDiskDatabaseConnection, oaPattern);
|
|
NS_ENSURE_SUCCESS_VOID(rv);
|
|
self->DecrementPendingWrites();
|
|
}),
|
|
NS_DISPATCH_EVENT_MAY_BLOCK);
|
|
return NS_OK;
|
|
}
|
|
|
|
NS_IMETHODIMP IdentityCredentialStorageService::DeleteFromTimeRange(
|
|
int64_t aStart, int64_t aEnd) {
|
|
AssertIsOnMainThread();
|
|
nsresult rv;
|
|
rv = WaitForInitialization();
|
|
NS_ENSURE_SUCCESS(rv, rv);
|
|
rv = DeleteDataFromTimeRange(mMemoryDatabaseConnection, aStart, aEnd);
|
|
NS_ENSURE_SUCCESS(rv, rv);
|
|
IncrementPendingWrites();
|
|
RefPtr<IdentityCredentialStorageService> self = this;
|
|
mBackgroundThread->Dispatch(
|
|
NS_NewRunnableFunction("IdentityCredentialStorageService::Init",
|
|
[self, aStart, aEnd]() {
|
|
nsresult rv = DeleteDataFromTimeRange(
|
|
self->mDiskDatabaseConnection, aStart, aEnd);
|
|
NS_ENSURE_SUCCESS_VOID(rv);
|
|
self->DecrementPendingWrites();
|
|
}),
|
|
NS_DISPATCH_EVENT_MAY_BLOCK);
|
|
return NS_OK;
|
|
}
|
|
|
|
NS_IMETHODIMP IdentityCredentialStorageService::
|
|
IdentityCredentialStorageService::DeleteFromPrincipal(
|
|
nsIPrincipal* aRPPrincipal) {
|
|
AssertIsOnMainThread();
|
|
NS_ENSURE_ARG_POINTER(aRPPrincipal);
|
|
nsresult rv =
|
|
IdentityCredentialStorageService::ValidatePrincipal(aRPPrincipal);
|
|
NS_ENSURE_SUCCESS(rv, rv);
|
|
|
|
rv = DeleteDataFromPrincipal(mMemoryDatabaseConnection, aRPPrincipal);
|
|
NS_ENSURE_SUCCESS(rv, rv);
|
|
IncrementPendingWrites();
|
|
RefPtr<IdentityCredentialStorageService> self = this;
|
|
RefPtr<nsIPrincipal> principal = aRPPrincipal;
|
|
mBackgroundThread->Dispatch(
|
|
NS_NewRunnableFunction("IdentityCredentialStorageService::Init",
|
|
[self, principal]() {
|
|
nsresult rv = DeleteDataFromPrincipal(
|
|
self->mDiskDatabaseConnection, principal);
|
|
NS_ENSURE_SUCCESS_VOID(rv);
|
|
self->DecrementPendingWrites();
|
|
}),
|
|
NS_DISPATCH_EVENT_MAY_BLOCK);
|
|
|
|
return NS_OK;
|
|
}
|
|
|
|
NS_IMETHODIMP IdentityCredentialStorageService::DeleteFromBaseDomain(
|
|
nsACString const& aBaseDomain) {
|
|
AssertIsOnMainThread();
|
|
nsresult rv;
|
|
rv = WaitForInitialization();
|
|
NS_ENSURE_SUCCESS(rv, rv);
|
|
rv = DeleteDataFromBaseDomain(mMemoryDatabaseConnection, aBaseDomain);
|
|
NS_ENSURE_SUCCESS(rv, rv);
|
|
IncrementPendingWrites();
|
|
RefPtr<IdentityCredentialStorageService> self = this;
|
|
nsCString baseDomain(aBaseDomain);
|
|
mBackgroundThread->Dispatch(
|
|
NS_NewRunnableFunction("IdentityCredentialStorageService::Init",
|
|
[self, baseDomain]() {
|
|
nsresult rv = DeleteDataFromBaseDomain(
|
|
self->mDiskDatabaseConnection, baseDomain);
|
|
NS_ENSURE_SUCCESS_VOID(rv);
|
|
self->DecrementPendingWrites();
|
|
}),
|
|
NS_DISPATCH_EVENT_MAY_BLOCK);
|
|
return NS_OK;
|
|
}
|
|
|
|
NS_IMETHODIMP
|
|
IdentityCredentialStorageService::Observe(nsISupports* aSubject,
|
|
const char* aTopic,
|
|
const char16_t* aData) {
|
|
AssertIsOnMainThread();
|
|
// Double check that we have the right topic.
|
|
if (!nsCRT::strcmp(aTopic, "last-pb-context-exited")) {
|
|
MonitorAutoLock lock(mMonitor);
|
|
if (mInitialized && mMemoryDatabaseConnection) {
|
|
nsCOMPtr<mozIStorageFunction> patternMatchFunction(
|
|
new PrivateBrowsingOriginSQLFunction());
|
|
nsresult rv = mMemoryDatabaseConnection->CreateFunction(
|
|
"PRIVATE_BROWSING_PATTERN_MATCH_ORIGIN"_ns, 1, patternMatchFunction);
|
|
NS_ENSURE_SUCCESS(rv, rv);
|
|
|
|
rv = mMemoryDatabaseConnection->ExecuteSimpleSQL(
|
|
"DELETE FROM identity WHERE "
|
|
"PRIVATE_BROWSING_PATTERN_MATCH_ORIGIN(rpOrigin);"_ns);
|
|
NS_ENSURE_SUCCESS(rv, rv);
|
|
|
|
rv = mMemoryDatabaseConnection->RemoveFunction(
|
|
"PRIVATE_BROWSING_PATTERN_MATCH_ORIGIN"_ns);
|
|
NS_ENSURE_SUCCESS(rv, rv);
|
|
}
|
|
}
|
|
return NS_OK;
|
|
}
|
|
|
|
NS_IMPL_ISUPPORTS(OriginAttrsPatternMatchOriginSQLFunction, mozIStorageFunction)
|
|
|
|
NS_IMETHODIMP
|
|
OriginAttrsPatternMatchOriginSQLFunction::OnFunctionCall(
|
|
mozIStorageValueArray* aFunctionArguments, nsIVariant** aResult) {
|
|
nsresult rv;
|
|
|
|
nsAutoCString origin;
|
|
rv = aFunctionArguments->GetUTF8String(0, origin);
|
|
NS_ENSURE_SUCCESS(rv, rv);
|
|
|
|
nsCString originNoSuffix;
|
|
OriginAttributes oa;
|
|
bool parsedSuccessfully = oa.PopulateFromOrigin(origin, originNoSuffix);
|
|
NS_ENSURE_TRUE(parsedSuccessfully, NS_ERROR_FAILURE);
|
|
bool result = mPattern.Matches(oa);
|
|
|
|
RefPtr<nsVariant> outVar(new nsVariant());
|
|
rv = outVar->SetAsBool(result);
|
|
NS_ENSURE_SUCCESS(rv, rv);
|
|
|
|
outVar.forget(aResult);
|
|
return NS_OK;
|
|
}
|
|
|
|
NS_IMPL_ISUPPORTS(PrivateBrowsingOriginSQLFunction, mozIStorageFunction)
|
|
|
|
NS_IMETHODIMP
|
|
PrivateBrowsingOriginSQLFunction::OnFunctionCall(
|
|
mozIStorageValueArray* aFunctionArguments, nsIVariant** aResult) {
|
|
nsresult rv;
|
|
|
|
nsAutoCString origin;
|
|
rv = aFunctionArguments->GetUTF8String(0, origin);
|
|
NS_ENSURE_SUCCESS(rv, rv);
|
|
|
|
bool result = OriginAttributes::IsPrivateBrowsing(origin);
|
|
|
|
RefPtr<nsVariant> outVar(new nsVariant());
|
|
rv = outVar->SetAsBool(result);
|
|
NS_ENSURE_SUCCESS(rv, rv);
|
|
|
|
outVar.forget(aResult);
|
|
return NS_OK;
|
|
}
|
|
|
|
} // namespace mozilla
|