https://bugs.webkit.org/show_bug.cgi?id=190466
Patch by Alejandro G. Castro <alex@igalia.com> on 2018-12-21
Reviewed by Youenn Fablet.
Source/WebCore:
Added persistency to the DeviceIdHashSaltStorage.
* platform/glib/FileSystemGlib.cpp:
(WebCore::FileSystem::getFileSize): Implemented this function to
allow sharing code with the statistics storage class.
* platform/glib/KeyedDecoderGlib.cpp:
(WebCore::KeyedDecoderGlib::dictionaryFromGVariant): Added a
condition to control situations where the key is empty, it can
happen if the user modifies the file in the disk.
* Modules/indexeddb/shared/IDBResourceIdentifier.cpp: Add include
to make work compilation with debug, unified builds.
Source/WebKit:
Added persistency to the DeviceIdHashSaltStorage. Implemented a
decoder and an encoder for the HashSaltForOrigin struct to store
it in a file, this allows us to save the lastTimeUsed, the origin
and the hash salt. It uses a new directory where it creates a file
per hash salt, the name of the file is the hash salt to avoid
leaking information in the system. The last time used and the
origin are stored inside the file, it also adds a version
directory used to change the structure of the file in the future,
if we need to do it. In the DeviceIdHashSaltStorage class the disk
operations happen in a WorkQueue, but all interactions go in the
main thread. We added code to handle the operations when the load
still did not finish.
* Platform/Logging.h:
Added channel DiskPersistency..
* Sources.txt: Added new files.
* UIProcess/API/APIProcessPoolConfiguration.cpp: Added code to set
the directory for the deviceIdHashSalts. That way we can use the
configuration when creating the DeviceIdHashSaltStorage.
(API::ProcessPoolConfiguration::createWithWebsiteDataStoreConfiguration):
(API::ProcessPoolConfiguration::ProcessPoolConfiguration):
(API::ProcessPoolConfiguration::copy):
* UIProcess/API/APIProcessPoolConfiguration.h:
* UIProcess/API/APIWebsiteDataStore.cpp:
(API::WebsiteDataStore::legacyDefaultDataStoreConfiguration):
Added code to set the directory in the disk used to store the
information.
* UIProcess/API/APIWebsiteDataStore.h: Ditto.
* UIProcess/API/Cocoa/APIWebsiteDataStoreCocoa.mm: Added dummy
implementation to get the directory in cocoa.
(API::WebsiteDataStore::defaultDeviceIdHashSaltsStorageDirectory):
(API::WebsiteDataStore::legacyDefaultDeviceIdHashSaltsStorageDirectory):
* UIProcess/API/glib/APIWebsiteDataStoreGLib.cpp: Defined the
default directories used to store the information in the disk.
(API::WebsiteDataStore::defaultDeviceIdHashSaltsStorageDirectory):
(API::WebsiteDataStore::legacyDefaultDeviceIdHashSaltsStorageDirectory):
(API::WebsiteDataStore::defaultDataStoreConfiguration):
* UIProcess/API/glib/WebKitWebsiteDataManager.cpp:
(webkitWebsiteDataManagerGetDataStore): Added the directory used
to store the information.
(webkit_website_data_manager_remove): Modified the way we use to
make sure when we remove the cookies we also remove the hash salts.
* UIProcess/API/win/APIWebsiteDataStoreWin.cpp: Added dummy
implementations to get the directory in windows platform.
(API::WebsiteDataStore::defaultDeviceIdHashSaltsStorageDirectory):
(API::WebsiteDataStore::legacyDefaultDeviceIdHashSaltsStorageDirectory):
* UIProcess/API/C/WKBackForwardListItemRef.cpp: Add namespace, it
seems some unified build compilation issue.
* UIProcess/DeviceIdHashSaltStorage.cpp:
(WebKit::DeviceIdHashSaltStorage::create): Added a create method
used to pass the directory and the persistency status of the websitedatastore.
(WebKit::DeviceIdHashSaltStorage::completeHandler): Added to share
the code copying the origins to complete the get handler.
(WebKit::DeviceIdHashSaltStorage::completeDeviceIdHashSaltForOriginCall):
Added to share the code when completing the task of getting a new
hash salt.
(WebKit::DeviceIdHashSaltStorage::DeviceIdHashSaltStorage): Added
a new constructor for the create method.
(WebKit::getSecurityOriginData): Added to get the
SecurityOriginData from a field in the decoder and do all the
checks.
(WebKit::DeviceIdHashSaltStorage::loadStorageFromDisk): Open the
directory and restore all the hash salts from disk to the memory
structure.
(WebKit::DeviceIdHashSaltStorage::createEncoderFromData const):
Creates the decoder to store the HashSaltForOrigin structure.
(WebKit::DeviceIdHashSaltStorage::storeHashSaltToDisk): Write to
disk a decoder object created from a HashSaltForOrigin
structure. It uses the writeEncoderToDisk function.
(WebKit::DeviceIdHashSaltStorage::deviceIdHashSaltForOrigin): Make
sure we store in disk a new hash salt when it is generated and the
WebsiteDataStore is persistent. Add a completionHandler to return
the value found or generated, this way we can control if the
HashMap is already loaded from disk.
(WebKit::DeviceIdHashSaltStorage::getDeviceIdHashSaltOrigins):
Make sure we run the get in a queue now that we store information
in disk.
(WebKit::DeviceIdHashSaltStorage::deleteHashSaltFromDiskIfNeeded):
Added code to make sure we remove the files in disk.
(WebKit::DeviceIdHashSaltStorage::deleteDeviceIdHashSaltForOrigins):
Added code to use the deleteHashSaltFromDiskIfNeeded and remove the files in disk.
(WebKit::DeviceIdHashSaltStorage::deleteDeviceIdHashSaltOriginsModifiedSince):
Added code to use the deleteHashSaltFromDiskIfNeeded and remove the files in disk.
* UIProcess/DeviceIdHashSaltStorage.h: Ditto.
* UIProcess/PersistencyUtils.cpp: Added file to share the
persistency code with the ResourceLoadStatisticsPersistentStorage class.
(WebKit::createDecoderForFile): Ditto.
(WebKit::writeEncoderToDisk): Ditto.
* UIProcess/PersistencyUtils.h: Ditto.
* UIProcess/ResourceLoadStatisticsPersistentStorage.cpp: Use the
new PersistencyUtils functions shared with the
DeviceIdHashSaltStorage class.
(WebKit::ResourceLoadStatisticsPersistentStorage::refreshMemoryStoreFromDisk):
(WebKit::ResourceLoadStatisticsPersistentStorage::populateMemoryStoreFromDisk):
(WebKit::ResourceLoadStatisticsPersistentStorage::writeMemoryStoreToDisk):
* UIProcess/UserMediaPermissionRequestManagerProxy.cpp: After
changing the API of the deviceIdHashSaltForOrigin we now use a
completionHandler because it could happen the HashMap is not still
loaded and we would have to wait for it. We refactored the calls
to the method to use this new completionHandler.
(WebKit::UserMediaPermissionRequestManagerProxy::userMediaAccessWasGranted):
(WebKit::UserMediaPermissionRequestManagerProxy::requestUserMediaPermissionForFrame):
(WebKit::UserMediaPermissionRequestManagerProxy::enumerateMediaDevicesForFrame):
* UIProcess/WebsiteData/WebsiteDataStore.cpp:
(WebKit::WebsiteDataStore::WebsiteDataStore): Create the
DeviceIdHashSaltStorage class with the persistency information.
(WebKit::WebsiteDataStore::resolveDirectoriesIfNecessary): Make
sure we have the directory to store the information.
* UIProcess/WebsiteData/WebsiteDataStoreConfiguration.h: Add get
and set functions for the deviceHashSaltStorageDirectory.
* WebKit.xcodeproj/project.pbxproj: Added PersistencyUtils file to
the xcode compilation.
git-svn-id: https://svn.webkit.org/repository/webkit/trunk@239513
268f45cc-cd09-0410-ab3c-
d52691b4dbfc
+2018-12-21 Alejandro G. Castro <alex@igalia.com>
+
+ [GTK][WPE] Add DeviceIdHashSaltStorage disk persistence
+ https://bugs.webkit.org/show_bug.cgi?id=190466
+
+ Reviewed by Youenn Fablet.
+
+ Added persistency to the DeviceIdHashSaltStorage.
+
+ * platform/glib/FileSystemGlib.cpp:
+ (WebCore::FileSystem::getFileSize): Implemented this function to
+ allow sharing code with the statistics storage class.
+ * platform/glib/KeyedDecoderGlib.cpp:
+ (WebCore::KeyedDecoderGlib::dictionaryFromGVariant): Added a
+ condition to control situations where the key is empty, it can
+ happen if the user modifies the file in the disk.
+ * Modules/indexeddb/shared/IDBResourceIdentifier.cpp: Add include
+ to make work compilation with debug, unified builds.
+
2018-12-21 Zalan Bujtas <zalan@apple.com>
Synchronous media query evaluation could destroy current Frame/FrameView.
#include "IDBConnectionToServer.h"
#include "IDBRequest.h"
#include <wtf/MainThread.h>
+#include <wtf/text/StringConcatenateNumbers.h>
namespace WebCore {
return true;
}
-bool getFileSize(PlatformFileHandle, long long&)
+bool getFileSize(PlatformFileHandle handle, long long& resultSize)
{
- notImplemented();
- return false;
+ auto info = g_file_io_stream_query_info(handle, G_FILE_ATTRIBUTE_STANDARD_SIZE, nullptr, nullptr);
+ if (!info)
+ return false;
+
+ resultSize = g_file_info_get_size(info);
+ return true;
}
Optional<WallTime> getFileCreationTime(const String&)
g_variant_iter_init(&iter, variant);
const char* key;
GVariant* value;
- while (g_variant_iter_loop(&iter, "{&sv}", &key, &value))
- dictionary.set(String::fromUTF8(key), value);
+ while (g_variant_iter_loop(&iter, "{&sv}", &key, &value)) {
+ if (key)
+ dictionary.set(String::fromUTF8(key), value);
+ }
return dictionary;
}
+2018-12-21 Alejandro G. Castro <alex@igalia.com>
+
+ [GTK][WPE] Add DeviceIdHashSaltStorage disk persistence
+ https://bugs.webkit.org/show_bug.cgi?id=190466
+
+ Reviewed by Youenn Fablet.
+
+ Added persistency to the DeviceIdHashSaltStorage. Implemented a
+ decoder and an encoder for the HashSaltForOrigin struct to store
+ it in a file, this allows us to save the lastTimeUsed, the origin
+ and the hash salt. It uses a new directory where it creates a file
+ per hash salt, the name of the file is the hash salt to avoid
+ leaking information in the system. The last time used and the
+ origin are stored inside the file, it also adds a version
+ directory used to change the structure of the file in the future,
+ if we need to do it. In the DeviceIdHashSaltStorage class the disk
+ operations happen in a WorkQueue, but all interactions go in the
+ main thread. We added code to handle the operations when the load
+ still did not finish.
+
+ * Platform/Logging.h:
+ Added channel DiskPersistency..
+ * Sources.txt: Added new files.
+ * UIProcess/API/APIProcessPoolConfiguration.cpp: Added code to set
+ the directory for the deviceIdHashSalts. That way we can use the
+ configuration when creating the DeviceIdHashSaltStorage.
+ (API::ProcessPoolConfiguration::createWithWebsiteDataStoreConfiguration):
+ (API::ProcessPoolConfiguration::ProcessPoolConfiguration):
+ (API::ProcessPoolConfiguration::copy):
+ * UIProcess/API/APIProcessPoolConfiguration.h:
+ * UIProcess/API/APIWebsiteDataStore.cpp:
+ (API::WebsiteDataStore::legacyDefaultDataStoreConfiguration):
+ Added code to set the directory in the disk used to store the
+ information.
+ * UIProcess/API/APIWebsiteDataStore.h: Ditto.
+ * UIProcess/API/Cocoa/APIWebsiteDataStoreCocoa.mm: Added dummy
+ implementation to get the directory in cocoa.
+ (API::WebsiteDataStore::defaultDeviceIdHashSaltsStorageDirectory):
+ (API::WebsiteDataStore::legacyDefaultDeviceIdHashSaltsStorageDirectory):
+ * UIProcess/API/glib/APIWebsiteDataStoreGLib.cpp: Defined the
+ default directories used to store the information in the disk.
+ (API::WebsiteDataStore::defaultDeviceIdHashSaltsStorageDirectory):
+ (API::WebsiteDataStore::legacyDefaultDeviceIdHashSaltsStorageDirectory):
+ (API::WebsiteDataStore::defaultDataStoreConfiguration):
+ * UIProcess/API/glib/WebKitWebsiteDataManager.cpp:
+ (webkitWebsiteDataManagerGetDataStore): Added the directory used
+ to store the information.
+ (webkit_website_data_manager_remove): Modified the way we use to
+ make sure when we remove the cookies we also remove the hash salts.
+ * UIProcess/API/win/APIWebsiteDataStoreWin.cpp: Added dummy
+ implementations to get the directory in windows platform.
+ (API::WebsiteDataStore::defaultDeviceIdHashSaltsStorageDirectory):
+ (API::WebsiteDataStore::legacyDefaultDeviceIdHashSaltsStorageDirectory):
+ * UIProcess/API/C/WKBackForwardListItemRef.cpp: Add namespace, it
+ seems some unified build compilation issue.
+ * UIProcess/DeviceIdHashSaltStorage.cpp:
+ (WebKit::DeviceIdHashSaltStorage::create): Added a create method
+ used to pass the directory and the persistency status of the websitedatastore.
+ (WebKit::DeviceIdHashSaltStorage::completeHandler): Added to share
+ the code copying the origins to complete the get handler.
+ (WebKit::DeviceIdHashSaltStorage::completeDeviceIdHashSaltForOriginCall):
+ Added to share the code when completing the task of getting a new
+ hash salt.
+ (WebKit::DeviceIdHashSaltStorage::DeviceIdHashSaltStorage): Added
+ a new constructor for the create method.
+ (WebKit::getSecurityOriginData): Added to get the
+ SecurityOriginData from a field in the decoder and do all the
+ checks.
+ (WebKit::DeviceIdHashSaltStorage::loadStorageFromDisk): Open the
+ directory and restore all the hash salts from disk to the memory
+ structure.
+ (WebKit::DeviceIdHashSaltStorage::createEncoderFromData const):
+ Creates the decoder to store the HashSaltForOrigin structure.
+ (WebKit::DeviceIdHashSaltStorage::storeHashSaltToDisk): Write to
+ disk a decoder object created from a HashSaltForOrigin
+ structure. It uses the writeEncoderToDisk function.
+ (WebKit::DeviceIdHashSaltStorage::deviceIdHashSaltForOrigin): Make
+ sure we store in disk a new hash salt when it is generated and the
+ WebsiteDataStore is persistent. Add a completionHandler to return
+ the value found or generated, this way we can control if the
+ HashMap is already loaded from disk.
+ (WebKit::DeviceIdHashSaltStorage::getDeviceIdHashSaltOrigins):
+ Make sure we run the get in a queue now that we store information
+ in disk.
+ (WebKit::DeviceIdHashSaltStorage::deleteHashSaltFromDiskIfNeeded):
+ Added code to make sure we remove the files in disk.
+ (WebKit::DeviceIdHashSaltStorage::deleteDeviceIdHashSaltForOrigins):
+ Added code to use the deleteHashSaltFromDiskIfNeeded and remove the files in disk.
+ (WebKit::DeviceIdHashSaltStorage::deleteDeviceIdHashSaltOriginsModifiedSince):
+ Added code to use the deleteHashSaltFromDiskIfNeeded and remove the files in disk.
+ * UIProcess/DeviceIdHashSaltStorage.h: Ditto.
+ * UIProcess/PersistencyUtils.cpp: Added file to share the
+ persistency code with the ResourceLoadStatisticsPersistentStorage class.
+ (WebKit::createDecoderForFile): Ditto.
+ (WebKit::writeEncoderToDisk): Ditto.
+ * UIProcess/PersistencyUtils.h: Ditto.
+ * UIProcess/ResourceLoadStatisticsPersistentStorage.cpp: Use the
+ new PersistencyUtils functions shared with the
+ DeviceIdHashSaltStorage class.
+ (WebKit::ResourceLoadStatisticsPersistentStorage::refreshMemoryStoreFromDisk):
+ (WebKit::ResourceLoadStatisticsPersistentStorage::populateMemoryStoreFromDisk):
+ (WebKit::ResourceLoadStatisticsPersistentStorage::writeMemoryStoreToDisk):
+ * UIProcess/UserMediaPermissionRequestManagerProxy.cpp: After
+ changing the API of the deviceIdHashSaltForOrigin we now use a
+ completionHandler because it could happen the HashMap is not still
+ loaded and we would have to wait for it. We refactored the calls
+ to the method to use this new completionHandler.
+ (WebKit::UserMediaPermissionRequestManagerProxy::userMediaAccessWasGranted):
+ (WebKit::UserMediaPermissionRequestManagerProxy::requestUserMediaPermissionForFrame):
+ (WebKit::UserMediaPermissionRequestManagerProxy::enumerateMediaDevicesForFrame):
+ * UIProcess/WebsiteData/WebsiteDataStore.cpp:
+ (WebKit::WebsiteDataStore::WebsiteDataStore): Create the
+ DeviceIdHashSaltStorage class with the persistency information.
+ (WebKit::WebsiteDataStore::resolveDirectoriesIfNecessary): Make
+ sure we have the directory to store the information.
+ * UIProcess/WebsiteData/WebsiteDataStoreConfiguration.h: Add get
+ and set functions for the deviceHashSaltStorageDirectory.
+ * WebKit.xcodeproj/project.pbxproj: Added PersistencyUtils file to
+ the xcode compilation.
+
2018-12-20 Alex Christensen <achristensen@webkit.org>
Remove unused NetworkProcessCreationParameters
M(CacheStorage) \
M(ContentObservation) \
M(ContextMenu) \
+ M(DiskPersistency) \
M(DragAndDrop) \
M(Fullscreen) \
M(Gamepad) \
UIProcess/BackgroundProcessResponsivenessTimer.cpp
UIProcess/ChildProcessProxy.cpp
+UIProcess/DeviceIdHashSaltStorage.cpp
UIProcess/DrawingAreaProxy.cpp
UIProcess/FrameLoadState.cpp
UIProcess/GeolocationPermissionRequestManagerProxy.cpp
UIProcess/GeolocationPermissionRequestProxy.cpp
UIProcess/InspectorTargetProxy.cpp
UIProcess/PageLoadState.cpp
-UIProcess/DeviceIdHashSaltStorage.cpp
+UIProcess/PersistencyUtils.cpp
UIProcess/ProcessAssertion.cpp
UIProcess/ProcessThrottler.cpp
UIProcess/RemoteWebInspectorProxy.cpp
configuration->m_mediaCacheDirectory = legacyConfiguration.mediaCacheDirectory();
configuration->m_indexedDBDatabaseDirectory = WebsiteDataStore::legacyDefaultIndexedDBDatabaseDirectory();
configuration->m_localStorageDirectory = legacyConfiguration.localStorageDirectory();
+ configuration->m_deviceIdHashSaltsStorageDirectory = legacyConfiguration.deviceIdHashSaltsStorageDirectory();
configuration->m_mediaKeysStorageDirectory = legacyConfiguration.mediaKeysStorageDirectory();
configuration->m_resourceLoadStatisticsDirectory = legacyConfiguration.resourceLoadStatisticsDirectory();
configuration->m_webSQLDatabaseDirectory = legacyConfiguration.webSQLDatabaseDirectory();
, m_mediaCacheDirectory(WebsiteDataStore::defaultMediaCacheDirectory())
, m_indexedDBDatabaseDirectory(WebsiteDataStore::defaultIndexedDBDatabaseDirectory())
, m_localStorageDirectory(WebsiteDataStore::defaultLocalStorageDirectory())
+ , m_deviceIdHashSaltsStorageDirectory(WebsiteDataStore::defaultDeviceIdHashSaltsStorageDirectory())
, m_webSQLDatabaseDirectory(WebsiteDataStore::defaultWebSQLDatabaseDirectory())
, m_mediaKeysStorageDirectory(WebsiteDataStore::defaultMediaKeysStorageDirectory())
, m_resourceLoadStatisticsDirectory(WebsiteDataStore::defaultResourceLoadStatisticsDirectory())
copy->m_indexedDBDatabaseDirectory = this->m_indexedDBDatabaseDirectory;
copy->m_injectedBundlePath = this->m_injectedBundlePath;
copy->m_localStorageDirectory = this->m_localStorageDirectory;
+ copy->m_deviceIdHashSaltsStorageDirectory = this->m_deviceIdHashSaltsStorageDirectory;
copy->m_mediaKeysStorageDirectory = this->m_mediaKeysStorageDirectory;
copy->m_resourceLoadStatisticsDirectory = this->m_resourceLoadStatisticsDirectory;
copy->m_javaScriptConfigurationDirectory = this->m_javaScriptConfigurationDirectory;
const WTF::String& localStorageDirectory() const { return m_localStorageDirectory; }
void setLocalStorageDirectory(const WTF::String& localStorageDirectory) { m_localStorageDirectory = localStorageDirectory; }
+ const WTF::String& deviceIdHashSaltsStorageDirectory() const { return m_deviceIdHashSaltsStorageDirectory; }
+ void setDeviceIdHashSaltsStorageDirectory(const WTF::String& directory) { m_deviceIdHashSaltsStorageDirectory = directory; }
+
const WTF::String& webSQLDatabaseDirectory() const { return m_webSQLDatabaseDirectory; }
void setWebSQLDatabaseDirectory(const WTF::String& webSQLDatabaseDirectory) { m_webSQLDatabaseDirectory = webSQLDatabaseDirectory; }
WTF::String m_indexedDBDatabaseDirectory;
WTF::String m_injectedBundlePath;
WTF::String m_localStorageDirectory;
+ WTF::String m_deviceIdHashSaltsStorageDirectory;
WTF::String m_webSQLDatabaseDirectory;
WTF::String m_mediaKeysStorageDirectory;
WTF::String m_resourceLoadStatisticsDirectory;
configuration->setNetworkCacheDirectory(legacyDefaultNetworkCacheDirectory());
configuration->setMediaCacheDirectory(legacyDefaultMediaCacheDirectory());
configuration->setMediaKeysStorageDirectory(legacyDefaultMediaKeysStorageDirectory());
+ configuration->setDeviceIdHashSaltsStorageDirectory(legacyDefaultDeviceIdHashSaltsStorageDirectory());
configuration->setIndexedDBDatabaseDirectory(legacyDefaultIndexedDBDatabaseDirectory());
configuration->setWebSQLDatabaseDirectory(legacyDefaultWebSQLDatabaseDirectory());
configuration->setLocalStorageDirectory(legacyDefaultLocalStorageDirectory());
static WTF::String defaultServiceWorkerRegistrationDirectory();
static WTF::String defaultLocalStorageDirectory();
static WTF::String defaultMediaKeysStorageDirectory();
+ static WTF::String defaultDeviceIdHashSaltsStorageDirectory();
static WTF::String defaultWebSQLDatabaseDirectory();
static WTF::String defaultResourceLoadStatisticsDirectory();
static WTF::String defaultJavaScriptConfigurationDirectory();
static WTF::String legacyDefaultIndexedDBDatabaseDirectory();
static WTF::String legacyDefaultWebSQLDatabaseDirectory();
static WTF::String legacyDefaultMediaKeysStorageDirectory();
+ static WTF::String legacyDefaultDeviceIdHashSaltsStorageDirectory();
static WTF::String legacyDefaultMediaCacheDirectory();
static WTF::String legacyDefaultJavaScriptConfigurationDirectory();
#include "WKAPICast.h"
#include "WebBackForwardListItem.h"
+using namespace WebKit;
+
WKTypeID WKBackForwardListItemGetTypeID()
{
return WebKit::toAPI(WebBackForwardListItem::APIType);
return websiteDataDirectoryFileSystemRepresentation("MediaKeys");
}
+WTF::String WebsiteDataStore::defaultDeviceIdHashSaltsStorageDirectory()
+{
+ // Not implemented.
+ return String();
+}
+
WTF::String WebsiteDataStore::defaultWebSQLDatabaseDirectory()
{
return websiteDataDirectoryFileSystemRepresentation("WebSQL");
return WebKit::stringByResolvingSymlinksInPath([mediaKeysStorageDirectory stringByStandardizingPath]);
}
+WTF::String WebsiteDataStore::legacyDefaultDeviceIdHashSaltsStorageDirectory()
+{
+ // Not implemented.
+ return String();
+}
+
WTF::String WebsiteDataStore::legacyDefaultJavaScriptConfigurationDirectory()
{
#if PLATFORM(IOS_FAMILY)
return websiteDataDirectoryFileSystemRepresentation(BASE_DIRECTORY G_DIR_SEPARATOR_S "mediakeys");
}
+String WebsiteDataStore::defaultDeviceIdHashSaltsStorageDirectory()
+{
+ return websiteDataDirectoryFileSystemRepresentation(BASE_DIRECTORY G_DIR_SEPARATOR_S "deviceidhashsalts");
+}
+
WTF::String WebsiteDataStore::defaultWebSQLDatabaseDirectory()
{
return websiteDataDirectoryFileSystemRepresentation(BASE_DIRECTORY G_DIR_SEPARATOR_S "databases");
return defaultMediaKeysStorageDirectory();
}
+String WebsiteDataStore::legacyDefaultDeviceIdHashSaltsStorageDirectory()
+{
+#if PLATFORM(WPE)
+ GUniquePtr<gchar> deviceIdHashSaltsStorageDirectory(g_build_filename(g_get_user_data_dir(), "wpe", "deviceidhashsalts", nullptr));
+ return WebCore::FileSystem::stringFromFileSystemRepresentation(deviceIdHashSaltsStorageDirectory.get());
+#endif
+ return defaultDeviceIdHashSaltsStorageDirectory();
+}
+
WTF::String WebsiteDataStore::legacyDefaultJavaScriptConfigurationDirectory()
{
GUniquePtr<gchar> javaScriptCoreConfigDirectory(g_build_filename(g_get_user_data_dir(), BASE_DIRECTORY, "JavaScriptCoreDebug", nullptr));
configuration->setLocalStorageDirectory(defaultLocalStorageDirectory());
configuration->setMediaKeysStorageDirectory(defaultMediaKeysStorageDirectory());
configuration->setResourceLoadStatisticsDirectory(defaultResourceLoadStatisticsDirectory());
+ configuration->setDeviceIdHashSaltsStorageDirectory(defaultDeviceIdHashSaltsStorageDirectory());
return configuration;
}
} // namespace API
+
configuration->setNetworkCacheDirectory(String(processPoolconfigurarion.diskCacheDirectory()));
configuration->setWebSQLDatabaseDirectory(String(processPoolconfigurarion.webSQLDatabaseDirectory()));
configuration->setLocalStorageDirectory(String(processPoolconfigurarion.localStorageDirectory()));
+ configuration->setDeviceIdHashSaltsStorageDirectory(String(processPoolconfigurarion.deviceIdHashSaltsStorageDirectory()));
configuration->setMediaKeysStorageDirectory(String(processPoolconfigurarion.mediaKeysStorageDirectory()));
return configuration;
}
g_return_if_fail(WEBKIT_IS_WEBSITE_DATA_MANAGER(manager));
g_return_if_fail(websiteData);
+ // We have to remove the hash salts when cookies are removed.
+ if (types & WEBKIT_WEBSITE_DATA_COOKIES)
+ types = static_cast<WebKitWebsiteDataTypes>(types | WEBKIT_WEBSITE_DATA_DEVICE_ID_HASH_SALT);
+
Vector<WebsiteDataRecord> records;
for (GList* item = websiteData; item; item = g_list_next(item)) {
WebKitWebsiteData* data = static_cast<WebKitWebsiteData*>(item->data);
- // We have to remove the hash salts when cookies are removed.
- auto dataTypes = webkit_website_data_get_types(data);
- if (dataTypes & WEBKIT_WEBSITE_DATA_DEVICE_ID_HASH_SALT)
- dataTypes = static_cast<WebKitWebsiteDataTypes>(dataTypes | WEBKIT_WEBSITE_DATA_COOKIES);
-
- if (dataTypes & types)
+ if (webkit_website_data_get_types(data) & types)
records.append(webkitWebsiteDataGetRecord(data));
}
return WebCore::FileSystem::pathByAppendingComponent(WebCore::FileSystem::localUserSpecificStorageDirectory(), "MediaKeyStorage");
}
+String WebsiteDataStore::defaultDeviceIdHashSaltsStorageDirectory()
+{
+ // Not Implemented.
+ return String();
+}
+
String WebsiteDataStore::defaultWebSQLDatabaseDirectory()
{
return WebCore::FileSystem::pathByAppendingComponent(WebCore::FileSystem::localUserSpecificStorageDirectory(), "WebSQL");
return WebCore::FileSystem::pathByAppendingComponent(WebCore::FileSystem::localUserSpecificStorageDirectory(), "MediaKeyStorage");
}
+String WebsiteDataStore::legacyDefaultDeviceIdHashSaltsStorageDirectory()
+{
+ // Not Implemented.
+ return String();
+}
+
String WebsiteDataStore::legacyDefaultJavaScriptConfigurationDirectory()
{
return WebCore::FileSystem::pathByAppendingComponent(WebCore::FileSystem::localUserSpecificStorageDirectory(), "JavaScriptCoreDebug");
#include "config.h"
#include "DeviceIdHashSaltStorage.h"
+#include "PersistencyUtils.h"
+
#include <WebCore/FileSystem.h>
+#include <WebCore/SharedBuffer.h>
#include <wtf/CryptographicallyRandomNumber.h>
#include <wtf/HexNumber.h>
#include <wtf/RunLoop.h>
#include <wtf/text/StringBuilder.h>
#include <wtf/text/StringHash.h>
-// FIXME: Implement persistency.
-
namespace WebKit {
using namespace WebCore;
-static const int hashSaltSize = 48;
-static const int randomDataSize = hashSaltSize / 16;
+static constexpr unsigned deviceIdHashSaltStorageVersion { 1 };
+static constexpr unsigned hashSaltSize { 48 };
+static constexpr unsigned randomDataSize { hashSaltSize / 16 };
+
+Ref<DeviceIdHashSaltStorage> DeviceIdHashSaltStorage::create(const String& deviceIdHashSaltStorageDirectory)
+{
+ auto deviceIdHashSaltStorage = adoptRef(*new DeviceIdHashSaltStorage(deviceIdHashSaltStorageDirectory));
+ return deviceIdHashSaltStorage;
+}
+
+void DeviceIdHashSaltStorage::completePendingHandler(CompletionHandler<void(HashSet<SecurityOriginData>&&)>&& completionHandler)
+{
+ ASSERT(RunLoop::isMain());
+
+ HashSet<SecurityOriginData> origins;
+
+ for (auto& hashSaltForOrigin : m_deviceIdHashSaltForOrigins) {
+ origins.add(hashSaltForOrigin.value->documentOrigin);
+ origins.add(hashSaltForOrigin.value->parentOrigin);
+ }
+
+ RunLoop::main().dispatch([origins = WTFMove(origins), completionHandler = WTFMove(completionHandler)]() mutable {
+ completionHandler(WTFMove(origins));
+ });
+}
+
+DeviceIdHashSaltStorage::DeviceIdHashSaltStorage(const String& deviceIdHashSaltStorageDirectory)
+ : m_queue(WorkQueue::create("com.apple.WebKit.DeviceIdHashSaltStorage"))
+ , m_deviceIdHashSaltStorageDirectory(!deviceIdHashSaltStorageDirectory.isEmpty() ? FileSystem::pathByAppendingComponent(deviceIdHashSaltStorageDirectory, String::number(deviceIdHashSaltStorageVersion)) : String())
+{
+ if (m_deviceIdHashSaltStorageDirectory.isEmpty()) {
+ m_isLoaded = true;
+ return;
+ }
+
+ loadStorageFromDisk([this, protectedThis = makeRef(*this)] (auto&& deviceIdHashSaltForOrigins) {
+ ASSERT(RunLoop::isMain());
+ m_deviceIdHashSaltForOrigins = WTFMove(deviceIdHashSaltForOrigins);
+ m_isLoaded = true;
+
+ auto pendingCompletionHandlers = WTFMove(m_pendingCompletionHandlers);
+ for (auto& completionHandler : pendingCompletionHandlers)
+ completionHandler();
+ });
+}
-Ref<DeviceIdHashSaltStorage> DeviceIdHashSaltStorage::create()
+DeviceIdHashSaltStorage::~DeviceIdHashSaltStorage()
{
- return adoptRef(*new DeviceIdHashSaltStorage());
+ auto pendingCompletionHandlers = WTFMove(m_pendingCompletionHandlers);
+ for (auto& completionHandler : pendingCompletionHandlers)
+ completionHandler();
}
-const String& DeviceIdHashSaltStorage::deviceIdHashSaltForOrigin(const SecurityOrigin& documentOrigin, const SecurityOrigin& parentOrigin)
+static WTF::Optional<SecurityOriginData> getSecurityOriginData(const char* name, KeyedDecoder* decoder)
{
- auto origins = makeString(documentOrigin.toRawString(), parentOrigin.toRawString());
- auto& deviceIdHashSalt = m_deviceIdHashSaltForOrigins.ensure(origins, [&documentOrigin, &parentOrigin] () {
+ String origin;
+
+ if (!decoder->decodeString(name, origin))
+ return WTF::nullopt;
+
+ auto securityOriginData = SecurityOriginData::fromDatabaseIdentifier(origin);
+ if (!securityOriginData)
+ return WTF::nullopt;
+
+ return securityOriginData;
+}
+
+void DeviceIdHashSaltStorage::loadStorageFromDisk(CompletionHandler<void(HashMap<String, std::unique_ptr<HashSaltForOrigin>>&&)>&& completionHandler)
+{
+ m_queue->dispatch([this, protectedThis = makeRef(*this), completionHandler = WTFMove(completionHandler)]() mutable {
+ ASSERT(!RunLoop::isMain());
+
+ FileSystem::makeAllDirectories(m_deviceIdHashSaltStorageDirectory);
+
+ auto originPaths = FileSystem::listDirectory(m_deviceIdHashSaltStorageDirectory, "*");
+
+ HashMap<String, std::unique_ptr<HashSaltForOrigin>> deviceIdHashSaltForOrigins;
+ for (const auto& originPath : originPaths) {
+ URL url;
+ url.setProtocol("file"_s);
+ url.setPath(originPath);
+
+ String deviceIdHashSalt = url.lastPathComponent();
+
+ if (hashSaltSize != deviceIdHashSalt.length()) {
+ RELEASE_LOG_ERROR(DiskPersistency, "DeviceIdHashSaltStorage: The length of the hash salt (%d) is different to the length of the hash salts defined in WebKit (%d)", deviceIdHashSalt.length(), hashSaltSize);
+ continue;
+ }
+
+ long long fileSize = 0;
+ if (!FileSystem::getFileSize(originPath, fileSize)) {
+ RELEASE_LOG_ERROR(DiskPersistency, "DeviceIdHashSaltStorage: Impossible to get the file size of: '%s'", originPath.utf8().data());
+ continue;
+ }
+
+ auto decoder = createForFile(originPath);
+
+ if (!decoder) {
+ RELEASE_LOG_ERROR(DiskPersistency, "DeviceIdHashSaltStorage: Impossible to access the file to restore the hash salt: '%s'", originPath.utf8().data());
+ continue;
+ }
+
+ auto hashSaltForOrigin = getDataFromDecoder(decoder.get(), WTFMove(deviceIdHashSalt));
+
+ auto origins = makeString(hashSaltForOrigin->documentOrigin.toString(), hashSaltForOrigin->parentOrigin.toString());
+ auto deviceIdHashSaltForOrigin = deviceIdHashSaltForOrigins.ensure(origins, [hashSaltForOrigin = WTFMove(hashSaltForOrigin)] () mutable {
+ return WTFMove(hashSaltForOrigin);
+ });
+
+ if (!deviceIdHashSaltForOrigin.isNewEntry)
+ RELEASE_LOG_ERROR(DiskPersistency, "DeviceIdHashSaltStorage: There are two files with different hash salts for the same origin: '%s'", originPath.utf8().data());
+ }
+
+ RunLoop::main().dispatch([deviceIdHashSaltForOrigins = WTFMove(deviceIdHashSaltForOrigins), completionHandler = WTFMove(completionHandler)]() mutable {
+ completionHandler(WTFMove(deviceIdHashSaltForOrigins));
+ });
+ });
+}
+
+std::unique_ptr<DeviceIdHashSaltStorage::HashSaltForOrigin> DeviceIdHashSaltStorage::getDataFromDecoder(KeyedDecoder* decoder, String&& deviceIdHashSalt) const
+{
+ auto securityOriginData = getSecurityOriginData("origin", decoder);
+ if (!securityOriginData) {
+ RELEASE_LOG_ERROR(DiskPersistency, "DeviceIdHashSaltStorage: The security origin data in the file is not correct: '%s'", deviceIdHashSalt.utf8().data());
+ return nullptr;
+ }
+
+ auto parentSecurityOriginData = getSecurityOriginData("parentOrigin", decoder);
+ if (!parentSecurityOriginData) {
+ RELEASE_LOG_ERROR(DiskPersistency, "DeviceIdHashSaltStorage: The parent security origin data in the file is not correct: '%s'", deviceIdHashSalt.utf8().data());
+ return nullptr;
+ }
+
+ double lastTimeUsed;
+ if (!decoder->decodeDouble("lastTimeUsed", lastTimeUsed)) {
+ RELEASE_LOG_ERROR(DiskPersistency, "DeviceIdHashSaltStorage: The last time used was not correctly restored for: '%s'", deviceIdHashSalt.utf8().data());
+ return nullptr;
+ }
+
+ auto hashSaltForOrigin = std::make_unique<HashSaltForOrigin>(WTFMove(securityOriginData.value()), WTFMove(parentSecurityOriginData.value()), WTFMove(deviceIdHashSalt));
+
+ hashSaltForOrigin->lastTimeUsed = WallTime::fromRawSeconds(lastTimeUsed);
+
+ return hashSaltForOrigin;
+}
+
+std::unique_ptr<KeyedEncoder> DeviceIdHashSaltStorage::createEncoderFromData(const HashSaltForOrigin& hashSaltForOrigin) const
+{
+ auto encoder = KeyedEncoder::encoder();
+ encoder->encodeString("origin", hashSaltForOrigin.documentOrigin.databaseIdentifier());
+ encoder->encodeString("parentOrigin", hashSaltForOrigin.parentOrigin.databaseIdentifier());
+ encoder->encodeDouble("lastTimeUsed", hashSaltForOrigin.lastTimeUsed.secondsSinceEpoch().value());
+ return encoder;
+}
+
+void DeviceIdHashSaltStorage::storeHashSaltToDisk(const HashSaltForOrigin& hashSaltForOrigin)
+{
+ if (m_deviceIdHashSaltStorageDirectory.isEmpty())
+ return;
+
+ m_queue->dispatch([this, protectedThis = makeRef(*this), hashSaltForOrigin = hashSaltForOrigin.isolatedCopy()]() mutable {
+ auto encoder = createEncoderFromData(hashSaltForOrigin);
+ writeToDisk(WTFMove(encoder), FileSystem::pathByAppendingComponent(m_deviceIdHashSaltStorageDirectory, hashSaltForOrigin.deviceIdHashSalt));
+ });
+}
+
+void DeviceIdHashSaltStorage::completeDeviceIdHashSaltForOriginCall(SecurityOriginData&& documentOrigin, SecurityOriginData&& parentOrigin, CompletionHandler<void(String&&)>&& completionHandler)
+{
+ auto origins = makeString(documentOrigin.toString(), parentOrigin.toString());
+ auto& deviceIdHashSalt = m_deviceIdHashSaltForOrigins.ensure(origins, [documentOrigin = WTFMove(documentOrigin), parentOrigin = WTFMove(parentOrigin)] () mutable {
uint64_t randomData[randomDataSize];
cryptographicallyRandomValues(reinterpret_cast<unsigned char*>(randomData), sizeof(randomData));
StringBuilder builder;
builder.reserveCapacity(hashSaltSize);
- for (int i = 0; i < randomDataSize; i++)
+ for (unsigned i = 0; i < randomDataSize; i++)
appendUnsigned64AsHex(randomData[i], builder);
String deviceIdHashSalt = builder.toString();
- return std::make_unique<HashSaltForOrigin>(documentOrigin.data().isolatedCopy(), parentOrigin.data().isolatedCopy(), WTFMove(deviceIdHashSalt));
+ auto newHashSaltForOrigin = std::make_unique<HashSaltForOrigin>(WTFMove(documentOrigin), WTFMove(parentOrigin), WTFMove(deviceIdHashSalt));
+
+ return newHashSaltForOrigin;
}).iterator->value;
deviceIdHashSalt->lastTimeUsed = WallTime::now();
- return deviceIdHashSalt->deviceIdHashSalt;
+ storeHashSaltToDisk(*deviceIdHashSalt.get());
+
+ completionHandler(String(deviceIdHashSalt->deviceIdHashSalt));
+}
+
+void DeviceIdHashSaltStorage::deviceIdHashSaltForOrigin(const SecurityOrigin& documentOrigin, const SecurityOrigin& parentOrigin, CompletionHandler<void(String&&)>&& completionHandler)
+{
+ ASSERT(RunLoop::isMain());
+
+ if (!m_isLoaded) {
+ m_pendingCompletionHandlers.append([this, documentOrigin = documentOrigin.data().isolatedCopy(), parentOrigin = parentOrigin.data().isolatedCopy(), completionHandler = WTFMove(completionHandler)]() mutable {
+ completeDeviceIdHashSaltForOriginCall(WTFMove(documentOrigin), WTFMove(parentOrigin), WTFMove(completionHandler));
+ });
+ return;
+ }
+
+ completeDeviceIdHashSaltForOriginCall(SecurityOriginData(documentOrigin.data()), SecurityOriginData(parentOrigin.data()), WTFMove(completionHandler));
}
void DeviceIdHashSaltStorage::getDeviceIdHashSaltOrigins(CompletionHandler<void(HashSet<SecurityOriginData>&&)>&& completionHandler)
{
- HashSet<SecurityOriginData> origins;
+ ASSERT(RunLoop::isMain());
- for (auto& hashSaltForOrigin : m_deviceIdHashSaltForOrigins) {
- origins.add(hashSaltForOrigin.value->documentOrigin);
- origins.add(hashSaltForOrigin.value->parentOrigin);
+ if (!m_isLoaded) {
+ m_pendingCompletionHandlers.append([this, completionHandler = WTFMove(completionHandler)]() mutable {
+ completePendingHandler(WTFMove(completionHandler));
+ });
+ return;
}
- RunLoop::main().dispatch([origins = WTFMove(origins), completionHandler = WTFMove(completionHandler)]() mutable {
- completionHandler(WTFMove(origins));
+ completePendingHandler(WTFMove(completionHandler));
+}
+
+void DeviceIdHashSaltStorage::deleteHashSaltFromDisk(const HashSaltForOrigin& hashSaltForOrigin)
+{
+ m_queue->dispatch([this, protectedThis = makeRef(*this), deviceIdHashSalt = hashSaltForOrigin.deviceIdHashSalt.isolatedCopy()]() mutable {
+ ASSERT(!RunLoop::isMain());
+
+ String fileFullPath = FileSystem::pathByAppendingComponent(m_deviceIdHashSaltStorageDirectory, deviceIdHashSalt.utf8().data());
+ FileSystem::deleteFile(fileFullPath);
});
}
void DeviceIdHashSaltStorage::deleteDeviceIdHashSaltForOrigins(const Vector<SecurityOriginData>& origins, CompletionHandler<void()>&& completionHandler)
{
- m_deviceIdHashSaltForOrigins.removeIf([&origins](auto& keyAndValue) {
- return origins.contains(keyAndValue.value->documentOrigin) || origins.contains(keyAndValue.value->parentOrigin);
+ ASSERT(RunLoop::isMain());
+
+ m_deviceIdHashSaltForOrigins.removeIf([this, &origins](auto& keyAndValue) {
+ bool needsRemoval = origins.contains(keyAndValue.value->documentOrigin) || origins.contains(keyAndValue.value->parentOrigin);
+ if (m_deviceIdHashSaltStorageDirectory.isEmpty())
+ return needsRemoval;
+ if (needsRemoval)
+ this->deleteHashSaltFromDisk(*keyAndValue.value.get());
+ return needsRemoval;
});
RunLoop::main().dispatch(WTFMove(completionHandler));
void DeviceIdHashSaltStorage::deleteDeviceIdHashSaltOriginsModifiedSince(WallTime time, CompletionHandler<void()>&& completionHandler)
{
- m_deviceIdHashSaltForOrigins.removeIf([time](auto& keyAndValue) {
- return keyAndValue.value->lastTimeUsed > time;
+ ASSERT(RunLoop::isMain());
+
+ m_deviceIdHashSaltForOrigins.removeIf([this, time](auto& keyAndValue) {
+ bool needsRemoval = keyAndValue.value->lastTimeUsed > time;
+ if (m_deviceIdHashSaltStorageDirectory.isEmpty())
+ return needsRemoval;
+ if (needsRemoval)
+ this->deleteHashSaltFromDisk(*keyAndValue.value.get());
+ return needsRemoval;
});
RunLoop::main().dispatch(WTFMove(completionHandler));
#pragma once
#include "UserMediaPermissionCheckProxy.h"
+#include <WebCore/KeyedCoding.h>
#include <WebCore/SecurityOrigin.h>
+#include <wtf/CompletionHandler.h>
#include <wtf/HashMap.h>
#include <wtf/HashSet.h>
#include <wtf/Ref.h>
+#include <wtf/WorkQueue.h>
namespace WebKit {
-class DeviceIdHashSaltStorage : public RefCounted<DeviceIdHashSaltStorage> {
+class DeviceIdHashSaltStorage : public ThreadSafeRefCounted<DeviceIdHashSaltStorage, WTF::DestructionThread::Main> {
public:
- static Ref<DeviceIdHashSaltStorage> create();
- ~DeviceIdHashSaltStorage() = default;
+ static Ref<DeviceIdHashSaltStorage> create(const String& deviceIdHashSaltStorageDirectory);
+ ~DeviceIdHashSaltStorage();
- const String& deviceIdHashSaltForOrigin(const WebCore::SecurityOrigin& documentOrigin, const WebCore::SecurityOrigin& parentOrigin);
+ void deviceIdHashSaltForOrigin(const WebCore::SecurityOrigin& documentOrigin, const WebCore::SecurityOrigin& parentOrigin, CompletionHandler<void(String&&)>&&);
void getDeviceIdHashSaltOrigins(CompletionHandler<void(HashSet<WebCore::SecurityOriginData>&&)>&&);
void deleteDeviceIdHashSaltForOrigins(const Vector<WebCore::SecurityOriginData>&, CompletionHandler<void()>&&);
, lastTimeUsed(WallTime::now())
{ };
+ HashSaltForOrigin isolatedCopy() const
+ {
+ auto isolatedCopy = HashSaltForOrigin(documentOrigin.isolatedCopy(), parentOrigin.isolatedCopy(), deviceIdHashSalt.isolatedCopy());
+ isolatedCopy.lastTimeUsed = lastTimeUsed;
+ return isolatedCopy;
+ };
+
WebCore::SecurityOriginData documentOrigin;
WebCore::SecurityOriginData parentOrigin;
String deviceIdHashSalt;
WallTime lastTimeUsed;
};
- DeviceIdHashSaltStorage() = default;
+ DeviceIdHashSaltStorage(const String& deviceIdHashSaltStorageDirectory);
+ void loadStorageFromDisk(CompletionHandler<void(HashMap<String, std::unique_ptr<HashSaltForOrigin>>&&)>&&);
+ void storeHashSaltToDisk(const HashSaltForOrigin&);
+ void deleteHashSaltFromDisk(const HashSaltForOrigin&);
+ std::unique_ptr<WebCore::KeyedEncoder> createEncoderFromData(const HashSaltForOrigin&) const;
+ std::unique_ptr<HashSaltForOrigin> getDataFromDecoder(WebCore::KeyedDecoder*, String&& deviceIdHashSalt) const;
+ void completePendingHandler(CompletionHandler<void(HashSet<WebCore::SecurityOriginData>&&)>&&);
+ void completeDeviceIdHashSaltForOriginCall(WebCore::SecurityOriginData&& documentOrigin, WebCore::SecurityOriginData&& parentOrigin, CompletionHandler<void(String&&)>&&);
+ Ref<WorkQueue> m_queue;
HashMap<String, std::unique_ptr<HashSaltForOrigin>> m_deviceIdHashSaltForOrigins;
+ bool m_isLoaded { false };
+ Vector<CompletionHandler<void()>> m_pendingCompletionHandlers;
+ const String m_deviceIdHashSaltStorageDirectory;
};
} // namespace WebKit
--- /dev/null
+/*
+ * Copyright (C) 2017-2018 Apple Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS''
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
+ * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
+ * THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "config.h"
+#include "PersistencyUtils.h"
+
+#include "Logging.h"
+#include <WebCore/FileSystem.h>
+#include <WebCore/SharedBuffer.h>
+#include <wtf/RunLoop.h>
+
+namespace WebKit {
+
+using namespace WebCore;
+
+std::unique_ptr<KeyedDecoder> createForFile(const String& path)
+{
+ ASSERT(!RunLoop::isMain());
+
+ auto handle = FileSystem::openAndLockFile(path, FileSystem::FileOpenMode::Read);
+ if (handle == FileSystem::invalidPlatformFileHandle)
+ return nullptr;
+
+ long long fileSize = 0;
+ if (!FileSystem::getFileSize(handle, fileSize) || !fileSize) {
+ FileSystem::unlockAndCloseFile(handle);
+ return nullptr;
+ }
+
+ size_t bytesToRead;
+ if (!WTF::convertSafely(fileSize, bytesToRead)) {
+ FileSystem::unlockAndCloseFile(handle);
+ return nullptr;
+ }
+
+ Vector<char> buffer(bytesToRead);
+ size_t totalBytesRead = FileSystem::readFromFile(handle, buffer.data(), buffer.size());
+
+ FileSystem::unlockAndCloseFile(handle);
+
+ if (totalBytesRead != bytesToRead)
+ return nullptr;
+
+ // FIXME: We should try to modify the constructor to pass &&.
+ return KeyedDecoder::decoder(reinterpret_cast<const uint8_t*>(buffer.data()), buffer.size());
+}
+
+void writeToDisk(std::unique_ptr<KeyedEncoder>&& encoder, String&& path)
+{
+ ASSERT(!RunLoop::isMain());
+
+ auto rawData = encoder->finishEncoding();
+ if (!rawData)
+ return;
+
+ FileSystem::PlatformFileHandle handle = FileSystem::openAndLockFile(path, FileSystem::FileOpenMode::Write);
+ if (handle == FileSystem::invalidPlatformFileHandle)
+ return;
+
+ auto writtenBytes = FileSystem::writeToFile(handle, rawData->data(), rawData->size());
+ FileSystem::unlockAndCloseFile(handle);
+
+ if (writtenBytes != static_cast<int64_t>(rawData->size()))
+ RELEASE_LOG_ERROR(DiskPersistency, "Disk persistency: We only wrote %d out of %zu bytes to disk", static_cast<unsigned>(writtenBytes), rawData->size());
+}
+
+} // namespace WebKit
--- /dev/null
+/*
+ * Copyright (C) 2017-2018 Apple Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS''
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
+ * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
+ * THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#pragma once
+
+#include <WebCore/KeyedCoding.h>
+
+namespace WebKit {
+
+std::unique_ptr<WebCore::KeyedDecoder> createForFile(const String& path);
+void writeToDisk(std::unique_ptr<WebCore::KeyedEncoder>&&, String&& path);
+
+} // namespace WebKit
return modificationTime.value() > since;
}
-static std::unique_ptr<KeyedDecoder> createDecoderForFile(const String& path)
-{
- ASSERT(!RunLoop::isMain());
- auto handle = FileSystem::openAndLockFile(path, FileSystem::FileOpenMode::Read);
- if (handle == FileSystem::invalidPlatformFileHandle)
- return nullptr;
-
- long long fileSize = 0;
- if (!FileSystem::getFileSize(handle, fileSize)) {
- FileSystem::unlockAndCloseFile(handle);
- return nullptr;
- }
-
- size_t bytesToRead;
- if (!WTF::convertSafely(fileSize, bytesToRead)) {
- FileSystem::unlockAndCloseFile(handle);
- return nullptr;
- }
-
- Vector<char> buffer(bytesToRead);
- size_t totalBytesRead = FileSystem::readFromFile(handle, buffer.data(), buffer.size());
-
- FileSystem::unlockAndCloseFile(handle);
-
- if (totalBytesRead != bytesToRead)
- return nullptr;
-
- return KeyedDecoder::decoder(reinterpret_cast<const uint8_t*>(buffer.data()), buffer.size());
-}
-
ResourceLoadStatisticsPersistentStorage::ResourceLoadStatisticsPersistentStorage(ResourceLoadStatisticsMemoryStore& memoryStore, WorkQueue& workQueue, const String& storageDirectoryPath)
: m_memoryStore(memoryStore)
, m_workQueue(workQueue)
WallTime readTime = WallTime::now();
- auto decoder = createDecoderForFile(filePath);
+ auto decoder = createForFile(filePath);
if (!decoder)
return;
WallTime readTime = WallTime::now();
- auto decoder = createDecoderForFile(filePath);
+ auto decoder = createForFile(filePath);
if (!decoder) {
m_memoryStore.grandfatherExistingWebsiteData([]() { });
return;
m_hasPendingWrite = false;
stopMonitoringDisk();
- auto encoder = m_memoryStore.createEncoderFromData();
- auto rawData = encoder->finishEncoding();
- if (!rawData)
- return;
-
- auto storagePath = storageDirectoryPath();
- if (!storagePath.isEmpty()) {
- FileSystem::makeAllDirectories(storagePath);
- excludeFromBackup();
- }
-
- auto handle = FileSystem::openAndLockFile(resourceLogFilePath(), FileSystem::FileOpenMode::Write);
- if (handle == FileSystem::invalidPlatformFileHandle)
- return;
-
- int64_t writtenBytes = FileSystem::writeToFile(handle, rawData->data(), rawData->size());
- FileSystem::unlockAndCloseFile(handle);
-
- if (writtenBytes != static_cast<int64_t>(rawData->size()))
- RELEASE_LOG_ERROR(ResourceLoadStatistics, "ResourceLoadStatisticsPersistentStorage: We only wrote %d out of %zu bytes to disk", static_cast<unsigned>(writtenBytes), rawData->size());
+ writeToDisk(m_memoryStore.createEncoderFromData(), resourceLogFilePath());
m_lastStatisticsFileSyncTime = WallTime::now();
m_lastStatisticsWriteTime = MonotonicTime::now();
if (!request)
return;
- auto deviceIDHashSalt = m_page.websiteDataStore().deviceIdHashSaltStorage()->deviceIdHashSaltForOrigin(request->userMediaDocumentSecurityOrigin(), request->topLevelDocumentSecurityOrigin());
-
- if (grantAccess(userMediaID, WTFMove(audioDevice), WTFMove(videoDevice), WTFMove(deviceIDHashSalt))) {
- m_grantedRequests.append(request.releaseNonNull());
- if (m_hasFilteredDeviceList)
- captureDevicesChanged();
- m_hasFilteredDeviceList = false;
- }
+ m_page.websiteDataStore().deviceIdHashSaltStorage()->deviceIdHashSaltForOrigin(request->userMediaDocumentSecurityOrigin(), request->topLevelDocumentSecurityOrigin(), [this, weakThis = makeWeakPtr(*this), userMediaID, audioDevice = WTFMove(audioDevice), videoDevice = WTFMove(videoDevice), localRequest = request.copyRef()] (String&& deviceIDHashSalt) mutable {
+ if (!weakThis)
+ return;
+ if (grantAccess(userMediaID, WTFMove(audioDevice), WTFMove(videoDevice), WTFMove(deviceIDHashSalt))) {
+ m_grantedRequests.append(localRequest.releaseNonNull());
+ if (m_hasFilteredDeviceList)
+ captureDevicesChanged();
+ m_hasFilteredDeviceList = false;
+ }
+ });
#else
UNUSED_PARAM(userMediaID);
UNUSED_PARAM(audioDevice);
syncWithWebCorePrefs();
- auto deviceIDHashSalt = m_page.websiteDataStore().deviceIdHashSaltStorage()->deviceIdHashSaltForOrigin(pendingRequest.value()->userMediaDocumentSecurityOrigin(), pendingRequest.value()->topLevelDocumentSecurityOrigin());
- RealtimeMediaSourceCenter::singleton().validateRequestConstraints(WTFMove(validHandler), WTFMove(invalidHandler), WTFMove(localUserRequest), WTFMove(deviceIDHashSalt));
+ m_page.websiteDataStore().deviceIdHashSaltStorage()->deviceIdHashSaltForOrigin(pendingRequest.value()->userMediaDocumentSecurityOrigin(), pendingRequest.value()->topLevelDocumentSecurityOrigin(), [validHandler = WTFMove(validHandler), invalidHandler = WTFMove(invalidHandler), localUserRequest = localUserRequest] (String&& deviceIDHashSalt) mutable {
+ RealtimeMediaSourceCenter::singleton().validateRequestConstraints(WTFMove(validHandler), WTFMove(invalidHandler), WTFMove(localUserRequest), WTFMove(deviceIDHashSalt));
+ });
};
getUserMediaPermissionInfo(requestID, frameID, WTFMove(havePermissionInfoHandler), WTFMove(userMediaDocumentOrigin), WTFMove(topLevelDocumentOrigin));
auto requestID = generateRequestID();
auto completionHandler = [this, requestID, userMediaID, requestOrigin = userMediaDocumentOrigin.copyRef(), topOrigin = topLevelDocumentOrigin.copyRef()](bool originHasPersistentAccess) {
- auto pendingRequest = m_pendingDeviceRequests.take(requestID);
- if (!pendingRequest)
- return;
-
- if (!m_page.isValid() || !m_page.websiteDataStore().deviceIdHashSaltStorage())
- return;
+ m_page.websiteDataStore().deviceIdHashSaltStorage()->deviceIdHashSaltForOrigin(requestOrigin.get(), topOrigin.get(), [this, weakThis = makeWeakPtr(*this), requestID, userMediaID, &originHasPersistentAccess] (String&& deviceIDHashSalt) {
+ if (!weakThis)
+ return;
+ auto pendingRequest = m_pendingDeviceRequests.take(requestID);
+ if (!pendingRequest)
+ return;
- syncWithWebCorePrefs();
+ if (!m_page.isValid() || !m_page.websiteDataStore().deviceIdHashSaltStorage())
+ return;
- auto devices = RealtimeMediaSourceCenter::singleton().getMediaStreamDevices();
- auto& request = *pendingRequest;
- bool revealIdsAndLabels = originHasPersistentAccess || wasGrantedVideoOrAudioAccess(request->frameID(), request->userMediaDocumentSecurityOrigin(), request->topLevelDocumentSecurityOrigin());
- int cameraCount = 0;
- int microphoneCount = 0;
- auto deviceIDHashSalt = m_page.websiteDataStore().deviceIdHashSaltStorage()->deviceIdHashSaltForOrigin(requestOrigin.get(), topOrigin.get());
+ syncWithWebCorePrefs();
- Vector<CaptureDevice> filteredDevices;
- for (const auto& device : devices) {
- if (!device.enabled() || (device.type() != WebCore::CaptureDevice::DeviceType::Camera && device.type() != WebCore::CaptureDevice::DeviceType::Microphone))
- continue;
+ auto devices = RealtimeMediaSourceCenter::singleton().getMediaStreamDevices();
+ auto& request = *pendingRequest;
+ bool revealIdsAndLabels = originHasPersistentAccess || wasGrantedVideoOrAudioAccess(request->frameID(), request->userMediaDocumentSecurityOrigin(), request->topLevelDocumentSecurityOrigin());
+ int cameraCount = 0;
+ int microphoneCount = 0;
- if (!revealIdsAndLabels) {
- if (device.type() == WebCore::CaptureDevice::DeviceType::Camera && ++cameraCount > defaultMaximumCameraCount)
+ Vector<CaptureDevice> filteredDevices;
+ for (const auto& device : devices) {
+ if (!device.enabled() || (device.type() != WebCore::CaptureDevice::DeviceType::Camera && device.type() != WebCore::CaptureDevice::DeviceType::Microphone))
continue;
- if (device.type() == WebCore::CaptureDevice::DeviceType::Microphone && ++microphoneCount > defaultMaximumMicrophoneCount)
- continue;
- }
- auto label = emptyString();
- auto id = emptyString();
- auto groupId = emptyString();
- if (revealIdsAndLabels) {
- label = device.label();
- id = RealtimeMediaSourceCenter::singleton().hashStringWithSalt(device.persistentId(), deviceIDHashSalt);
- groupId = RealtimeMediaSourceCenter::singleton().hashStringWithSalt(device.groupId(), deviceIDHashSalt);
+ if (!revealIdsAndLabels) {
+ if (device.type() == WebCore::CaptureDevice::DeviceType::Camera && ++cameraCount > defaultMaximumCameraCount)
+ continue;
+ if (device.type() == WebCore::CaptureDevice::DeviceType::Microphone && ++microphoneCount > defaultMaximumMicrophoneCount)
+ continue;
+ }
+
+ auto label = emptyString();
+ auto id = emptyString();
+ auto groupId = emptyString();
+ if (revealIdsAndLabels) {
+ label = device.label();
+ id = RealtimeMediaSourceCenter::singleton().hashStringWithSalt(device.persistentId(), deviceIDHashSalt);
+ groupId = RealtimeMediaSourceCenter::singleton().hashStringWithSalt(device.groupId(), deviceIDHashSalt);
+ }
+
+ filteredDevices.append(CaptureDevice(id, device.type(), label, groupId));
}
- filteredDevices.append(CaptureDevice(id, device.type(), label, groupId));
- }
-
- m_hasFilteredDeviceList = !revealIdsAndLabels;
+ m_hasFilteredDeviceList = !revealIdsAndLabels;
- m_page.process().send(Messages::WebPage::DidCompleteMediaDeviceEnumeration(userMediaID, WTFMove(filteredDevices), WTFMove(deviceIDHashSalt), originHasPersistentAccess), m_page.pageID());
+ m_page.process().send(Messages::WebPage::DidCompleteMediaDeviceEnumeration(userMediaID, WTFMove(filteredDevices), WTFMove(deviceIDHashSalt), originHasPersistentAccess), m_page.pageID());
+ });
};
getUserMediaPermissionInfo(requestID, frameID, WTFMove(completionHandler), WTFMove(userMediaDocumentOrigin), WTFMove(topLevelDocumentOrigin));
#include <wtf/HashMap.h>
#include <wtf/RunLoop.h>
#include <wtf/Seconds.h>
+#include <wtf/WeakPtr.h>
namespace WebCore {
class CaptureDevice;
class WebPageProxy;
-class UserMediaPermissionRequestManagerProxy {
+class UserMediaPermissionRequestManagerProxy : public CanMakeWeakPtr<UserMediaPermissionRequestManagerProxy> {
public:
explicit UserMediaPermissionRequestManagerProxy(WebPageProxy&);
~UserMediaPermissionRequestManagerProxy();
, m_resolvedConfiguration(WTFMove(configuration))
, m_configuration(m_resolvedConfiguration->copy())
, m_storageManager(StorageManager::create(m_configuration->localStorageDirectory()))
- , m_deviceIdHashSaltStorage(DeviceIdHashSaltStorage::create())
+ , m_deviceIdHashSaltStorage(DeviceIdHashSaltStorage::create(isPersistent() ? m_configuration->deviceIdHashSaltsStorageDirectory() : String()))
, m_queue(WorkQueue::create("com.apple.WebKit.WebsiteDataStore"))
#if ENABLE(WEB_AUTHN)
, m_authenticatorManager(makeUniqueRef<AuthenticatorManager>())
m_resolvedConfiguration->setWebSQLDatabaseDirectory(resolveAndCreateReadWriteDirectoryForSandboxExtension(m_configuration->webSQLDatabaseDirectory()));
if (!m_configuration->indexedDBDatabaseDirectory().isEmpty())
m_resolvedConfiguration->setIndexedDBDatabaseDirectory(resolveAndCreateReadWriteDirectoryForSandboxExtension(m_configuration->indexedDBDatabaseDirectory()));
+ if (!m_configuration->deviceIdHashSaltsStorageDirectory().isEmpty())
+ m_resolvedConfiguration->setDeviceIdHashSaltsStorageDirectory(resolveAndCreateReadWriteDirectoryForSandboxExtension(m_configuration->deviceIdHashSaltsStorageDirectory()));
if (!m_configuration->resourceLoadStatisticsDirectory().isEmpty())
m_resolvedConfiguration->setResourceLoadStatisticsDirectory(resolveAndCreateReadWriteDirectoryForSandboxExtension(m_configuration->resourceLoadStatisticsDirectory()));
if (!m_configuration->serviceWorkerRegistrationDirectory().isEmpty() && m_resolvedConfiguration->serviceWorkerRegistrationDirectory().isEmpty())
const String& localStorageDirectory() const { return m_localStorageDirectory; }
void setLocalStorageDirectory(String&& directory) { m_localStorageDirectory = WTFMove(directory); }
-
+
+ const String& deviceIdHashSaltsStorageDirectory() const { return m_deviceIdHashSaltsStorageDirectory; }
+ void setDeviceIdHashSaltsStorageDirectory(String&& directory) { m_deviceIdHashSaltsStorageDirectory = WTFMove(directory); }
+
const String& cookieStorageFile() const { return m_cookieStorageFile; }
void setCookieStorageFile(String&& directory) { m_cookieStorageFile = WTFMove(directory); }
00B9661A18E25AE100CE1F88 /* FindClient.h in Headers */ = {isa = PBXBuildFile; fileRef = 00B9661818E25AE100CE1F88 /* FindClient.h */; };
07297F9F1C17BBEA003F0735 /* UserMediaPermissionCheckProxy.h in Headers */ = {isa = PBXBuildFile; fileRef = 07297F9D1C17BBEA003F0735 /* UserMediaPermissionCheckProxy.h */; };
07297F9F1C17BBEA015F0735 /* DeviceIdHashSaltStorage.h in Headers */ = {isa = PBXBuildFile; fileRef = 07297F9D1C17BBEA223F0735 /* DeviceIdHashSaltStorage.h */; };
+ 07297F9F1C17AA1A015F0735 /* PersistencyUtils.h in Headers */ = {isa = PBXBuildFile; fileRef = 07321F9D1C17BBEA223F0735 /* PersistencyUtils.h */; };
07297FA31C186ADB003F0735 /* WKUserMediaPermissionCheck.h in Headers */ = {isa = PBXBuildFile; fileRef = 07297FA11C186ADB003F0735 /* WKUserMediaPermissionCheck.h */; settings = {ATTRIBUTES = (Private, ); }; };
074E75FE1DF2211900D318EC /* UserMediaProcessManager.h in Headers */ = {isa = PBXBuildFile; fileRef = 074E75FB1DF1FD1300D318EC /* UserMediaProcessManager.h */; };
076E884E1A13CADF005E90FC /* APIContextMenuClient.h in Headers */ = {isa = PBXBuildFile; fileRef = 076E884D1A13CADF005E90FC /* APIContextMenuClient.h */; };
07297F9C1C17BBEA003F0735 /* UserMediaPermissionCheckProxy.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = UserMediaPermissionCheckProxy.cpp; sourceTree = "<group>"; };
07297F9D1C17BBEA003F0735 /* UserMediaPermissionCheckProxy.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = UserMediaPermissionCheckProxy.h; sourceTree = "<group>"; };
07297F9D1C17BBEA223F0735 /* DeviceIdHashSaltStorage.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = DeviceIdHashSaltStorage.h; sourceTree = "<group>"; };
+ 0729455C1C1711EA003F0735 /* PersistencyUtils.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = PersistencyUtils.cpp; sourceTree = "<group>"; };
+ 07321F9D1C17BBEA223F0735 /* PersistencyUtils.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = PersistencyUtils.h; sourceTree = "<group>"; };
07297FA01C186ADB003F0735 /* WKUserMediaPermissionCheck.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = WKUserMediaPermissionCheck.cpp; sourceTree = "<group>"; };
07297FA11C186ADB003F0735 /* WKUserMediaPermissionCheck.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = WKUserMediaPermissionCheck.h; sourceTree = "<group>"; };
074E75FB1DF1FD1300D318EC /* UserMediaProcessManager.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = UserMediaProcessManager.h; sourceTree = "<group>"; };
1AC7537A183A9FDB0072CB15 /* PageLoadState.h */,
832ED1891E2FE13B006BA64A /* PerActivityStateCPUUsageSampler.cpp */,
832ED18A1E2FE13B006BA64A /* PerActivityStateCPUUsageSampler.h */,
+ 0729455C1C1711EA003F0735 /* PersistencyUtils.cpp */,
+ 07321F9D1C17BBEA223F0735 /* PersistencyUtils.h */,
37716A59195B910500EE8B1B /* ProcessAssertion.cpp */,
86F9536018FF4FD4001DB2EF /* ProcessAssertion.h */,
86E67A22190F411800004AB7 /* ProcessThrottler.cpp */,
2DC18FB0218912640025A88D /* PencilKitSPI.h in Headers */,
5C298DA01C3DF02100470AFE /* PendingDownload.h in Headers */,
832ED18C1E2FE157006BA64A /* PerActivityStateCPUUsageSampler.h in Headers */,
+ 07297F9F1C17AA1A015F0735 /* PersistencyUtils.h in Headers */,
5CE85B201C88E64B0070BFCE /* PingLoad.h in Headers */,
0F5E200418E77051003EC3E5 /* PlatformCAAnimationRemote.h in Headers */,
2DA049B4180CCCD300AAFA9E /* PlatformCALayerRemote.h in Headers */,