Skip to content

Commit

Permalink
Support declarativeNetRequest.getMatchedRules
Browse files Browse the repository at this point in the history
https://bugs.webkit.org/show_bug.cgi?id=265917
rdar://118940129

Reviewed by Timothy Hatcher.

This patch keeps track of the content rule list actions that each extension has performed and
exposes them through declarativeNetRequest.getMatchedRules().

These can be filtered on tabId and timeStamp, and are limited to only vending information about
URLs that the extension has access to.

* Source/WebKit/DerivedSources-input.xcfilelist:
* Source/WebKit/DerivedSources.make:
* Source/WebKit/Shared/Extensions/WebExtensionMatchedRuleParameters.h: Added.
* Source/WebKit/Shared/Extensions/WebExtensionMatchedRuleParameters.serialization.in: Added.
* Source/WebKit/UIProcess/Extensions/Cocoa/API/WebExtensionContextAPIDeclarativeNetRequestCocoa.mm:
(WebKit::WebExtensionContext::declarativeNetRequestGetMatchedRules): Iterate over the matched rules and
filter them. Also check to make sure we have permission to access the URLs before vending them.
* Source/WebKit/UIProcess/Extensions/Cocoa/WebExtensionContextCocoa.mm:
(WebKit::WebExtensionContext::unload): Clear the matched rules.
(WebKit::WebExtensionContext::handleContentRuleListNotificationForTab): Increment the blocked resource count
and add the blocked resource to the list of matched rules.
* Source/WebKit/UIProcess/Extensions/Cocoa/WebExtensionControllerCocoa.mm:
(WebKit::WebExtensionController::handleContentRuleListNotification):
* Source/WebKit/UIProcess/Extensions/WebExtensionContext.h:
(WebKit::WebExtensionContext::matchedRules): Keep track of the matched rules.
* Source/WebKit/UIProcess/Extensions/WebExtensionContext.messages.in:
* Source/WebKit/WebKit.xcodeproj/project.pbxproj:
* Source/WebKit/WebProcess/Extensions/API/Cocoa/WebExtensionAPIDeclarativeNetRequestCocoa.mm:
(WebKit::extensionHasPermission): Add a helper method.
(WebKit::toWebAPI): Ditto.
(WebKit::WebExtensionAPIDeclarativeNetRequest::getMatchedRules):
* Tools/TestWebKitAPI/Tests/WebKitCocoa/WKWebExtensionAPIDeclarativeNetRequest.mm:
(TestWebKitAPI::TEST): Add a test that getMatchedRules returns a match that the frame was blocked.

Canonical link: https://commits.webkit.org/271593@main
  • Loading branch information
b-weinstein committed Dec 6, 2023
1 parent 686826b commit e270f83
Show file tree
Hide file tree
Showing 13 changed files with 278 additions and 4 deletions.
1 change: 1 addition & 0 deletions Source/WebKit/DerivedSources-input.xcfilelist
Original file line number Diff line number Diff line change
Expand Up @@ -234,6 +234,7 @@ $(PROJECT_DIR)/Shared/Extensions/WebExtensionControllerParameters.serialization.
$(PROJECT_DIR)/Shared/Extensions/WebExtensionDynamicScripts.serialization.in
$(PROJECT_DIR)/Shared/Extensions/WebExtensionEventListenerType.serialization.in
$(PROJECT_DIR)/Shared/Extensions/WebExtensionFrameParameters.serialization.in
$(PROJECT_DIR)/Shared/Extensions/WebExtensionMatchedRuleParameters.serialization.in
$(PROJECT_DIR)/Shared/Extensions/WebExtensionMenuItem.serialization.in
$(PROJECT_DIR)/Shared/Extensions/WebExtensionMessageSenderParameters.serialization.in
$(PROJECT_DIR)/Shared/Extensions/WebExtensionTab.serialization.in
Expand Down
1 change: 1 addition & 0 deletions Source/WebKit/DerivedSources.make
Original file line number Diff line number Diff line change
Expand Up @@ -554,6 +554,7 @@ SERIALIZATION_DESCRIPTION_FILES = \
Shared/Extensions/WebExtensionDynamicScripts.serialization.in \
Shared/Extensions/WebExtensionEventListenerType.serialization.in \
Shared/Extensions/WebExtensionFrameParameters.serialization.in \
Shared/Extensions/WebExtensionMatchedRuleParameters.serialization.in \
Shared/Extensions/WebExtensionMenuItem.serialization.in \
Shared/Extensions/WebExtensionMessageSenderParameters.serialization.in \
Shared/Extensions/WebExtensionTab.serialization.in \
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
/*
* Copyright (C) 2023 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

#if ENABLE(WK_WEB_EXTENSIONS)

#include "WebExtensionTabIdentifier.h"
#include <wtf/URL.h>
#include <wtf/WallTime.h>

namespace WebKit {

struct WebExtensionMatchedRuleParameters {
URL url;
WallTime timeStamp;
WebExtensionTabIdentifier tabIdentifier;
};

} // namespace WebKit

#endif // ENABLE(WK_WEB_EXTENSIONS)
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
# Copyright (C) 2023 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.

#if ENABLE(WK_WEB_EXTENSIONS)

struct WebKit::WebExtensionMatchedRuleParameters {
URL url;
WallTime timeStamp;
WebKit::WebExtensionTabIdentifier tabIdentifier;
}

#endif
Original file line number Diff line number Diff line change
Expand Up @@ -222,6 +222,45 @@
completionHandler(std::nullopt);
}

void WebExtensionContext::declarativeNetRequestGetMatchedRules(std::optional<WebExtensionTabIdentifier> tabIdentifier, std::optional<WallTime> minTimeStamp, CompletionHandler<void(std::optional<Vector<WebExtensionMatchedRuleParameters>> matchedRules, std::optional<String>)>&& completionHandler)
{
RefPtr tab = tabIdentifier ? getTab(tabIdentifier.value()) : nullptr;

static NSString * const apiName = @"declarativeNetRequest.getMatchedRules()";
if (tabIdentifier && !tab) {
completionHandler(std::nullopt, toErrorString(apiName, nil, @"tab not found"));
return;
}

if (!hasPermission(_WKWebExtensionPermissionDeclarativeNetRequestFeedback)) {
ASSERT(hasPermission(_WKWebExtensionPermissionActiveTab));

if (!hasPermission(_WKWebExtensionPermissionTabs, tab.get())) {
completionHandler(std::nullopt, toErrorString(apiName, nil, @"The 'activeTab' permission has not been granted by the user for the specified tab."));
return;
}
}

WallTime minTime = minTimeStamp ? minTimeStamp.value() : WallTime::nan();

DeclarativeNetRequestMatchedRuleVector filteredMatchedRules;
for (auto matchedRule : matchedRules()) {
// FIXME: https://bugs.webkit.org/show_bug.cgi?id=262714 - we should be requesting permission if we don't have access to this URL.
if (!hasPermission(matchedRule.url))
continue;

if (tabIdentifier && matchedRule.tabIdentifier != tabIdentifier)
continue;

if (minTime != WallTime::nan() && matchedRule.timeStamp <= minTime)
continue;

filteredMatchedRules.append(matchedRule);
}

completionHandler(filteredMatchedRules, std::nullopt);
}

} // namespace WebKit

#endif // ENABLE(WK_WEB_EXTENSIONS)
Original file line number Diff line number Diff line change
Expand Up @@ -268,6 +268,8 @@ static _WKWebExtensionContextError toAPI(WebExtensionContext::Error error)
m_extensionController = nil;
m_contentScriptWorld = nullptr;

m_matchedRules.clear();

return true;
}

Expand Down Expand Up @@ -3010,6 +3012,23 @@ static _WKWebExtensionContextError toAPI(WebExtensionContext::Error error)
compileDeclarativeNetRequestRules(allJSONData, WTFMove(completionHandler));
}


void WebExtensionContext::handleContentRuleListNotificationForTab(WebExtensionTab& tab, const URL& url, WebCore::ContentRuleListResults::Result)
{
incrementActionCountForTab(tab, 1);

if (!hasPermission(_WKWebExtensionPermissionDeclarativeNetRequestFeedback) && !(hasPermission(_WKWebExtensionPermissionDeclarativeNetRequest) && hasPermission(_WKWebExtensionPermissionActiveTab)))
return;

// FIXME: rdar://118940129 - Set a timer to purge old matched rules.

m_matchedRules.append({
url,
WallTime::now(),
tab.identifier()
});
}

} // namespace WebKit

#endif // ENABLE(WK_WEB_EXTENSIONS)
Original file line number Diff line number Diff line change
Expand Up @@ -307,7 +307,7 @@
if (!tab)
break;

context->incrementActionCountForTab(*tab, 1);
context->handleContentRuleListNotificationForTab(*tab, url, result.second);
break;
}
}
Expand Down
8 changes: 8 additions & 0 deletions Source/WebKit/UIProcess/Extensions/WebExtensionContext.h
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,7 @@
#include "WebExtensionFrameIdentifier.h"
#include "WebExtensionFrameParameters.h"
#include "WebExtensionMatchPattern.h"
#include "WebExtensionMatchedRuleParameters.h"
#include "WebExtensionMenuItem.h"
#include "WebExtensionMessagePort.h"
#include "WebExtensionPortChannelIdentifier.h"
Expand All @@ -52,6 +53,7 @@
#include "WebExtensionWindowParameters.h"
#include "WebPageProxyIdentifier.h"
#include "WebProcessProxy.h"
#include <WebCore/ContentRuleListResults.h>
#include <wtf/CompletionHandler.h>
#include <wtf/Forward.h>
#include <wtf/HashCountedSet.h>
Expand Down Expand Up @@ -161,6 +163,7 @@ class WebExtensionContext : public API::ObjectImpl<API::Object::Type::WebExtensi
using MenuItemMap = HashMap<String, Ref<WebExtensionMenuItem>>;

using DeclarativeNetRequestValidatedRulesets = std::pair<std::optional<WebExtension::DeclarativeNetRequestRulesetVector>, std::optional<String>>;
using DeclarativeNetRequestMatchedRuleVector = Vector<WebExtensionMatchedRuleParameters>;

enum class EqualityOnly : bool { No, Yes };
enum class WindowIsClosing : bool { No, Yes };
Expand Down Expand Up @@ -365,6 +368,7 @@ class WebExtensionContext : public API::ObjectImpl<API::Object::Type::WebExtensi
void addInjectedContent(WebUserContentControllerProxy&);
void removeInjectedContent(WebUserContentControllerProxy&);

void handleContentRuleListNotificationForTab(WebExtensionTab&, const URL&, WebCore::ContentRuleListResults::Result);
void incrementActionCountForTab(WebExtensionTab&, ssize_t incrementAmount);

UserStyleSheetVector& dynamicallyInjectedUserStyleSheets() { return m_dynamicallyInjectedUserStyleSheets; };
Expand Down Expand Up @@ -464,6 +468,8 @@ class WebExtensionContext : public API::ObjectImpl<API::Object::Type::WebExtensi
bool shouldDisplayBlockedResourceCountAsBadgeText();
void saveShouldDisplayBlockedResourceCountAsBadgeText(bool);

DeclarativeNetRequestMatchedRuleVector matchedRules() { return m_matchedRules; }

// Action APIs
void actionGetTitle(std::optional<WebExtensionWindowIdentifier>, std::optional<WebExtensionTabIdentifier>, CompletionHandler<void(std::optional<String>, std::optional<String>)>&&);
void actionSetTitle(std::optional<WebExtensionWindowIdentifier>, std::optional<WebExtensionTabIdentifier>, const String& title, CompletionHandler<void(std::optional<String>)>&&);
Expand Down Expand Up @@ -498,6 +504,7 @@ class WebExtensionContext : public API::ObjectImpl<API::Object::Type::WebExtensi
DeclarativeNetRequestValidatedRulesets declarativeNetRequestValidateRulesetIdentifiers(const Vector<String>&);
size_t declarativeNetRequestEnabledRulesetCount();
void declarativeNetRequestToggleRulesets(const Vector<String>& rulesetIdentifiers, bool newValue, NSMutableDictionary *rulesetIdentifiersToEnabledState);
void declarativeNetRequestGetMatchedRules(std::optional<WebExtensionTabIdentifier>, std::optional<WallTime> minTimeStamp, CompletionHandler<void(std::optional<Vector<WebExtensionMatchedRuleParameters>> matchedRules, std::optional<String>)>&&);

// Event APIs
void addListener(WebPageProxyIdentifier, WebExtensionEventListenerType, WebExtensionContentWorldType);
Expand Down Expand Up @@ -689,6 +696,7 @@ class WebExtensionContext : public API::ObjectImpl<API::Object::Type::WebExtensi
bool m_populatedCommands { false };

RetainPtr<WKContentRuleListStore> m_declarativeNetRequestRuleStore;
DeclarativeNetRequestMatchedRuleVector m_matchedRules;

MenuItemMap m_menuItems;
MenuItemVector m_mainMenuItems;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -53,6 +53,7 @@ messages -> WebExtensionContext {
DeclarativeNetRequestUpdateEnabledRulesets(Vector<String> rulesetIdentifiersToEnable, Vector<String> rulesetIdentifiersToDisable) -> (std::optional<String> error);
DeclarativeNetRequestDisplayActionCountAsBadgeText(bool result) -> (std::optional<String> error);
DeclarativeNetRequestIncrementActionCount(WebKit::WebExtensionTabIdentifier tabIdentifier, double increment) -> (std::optional<String> error);
DeclarativeNetRequestGetMatchedRules(std::optional<WebKit::WebExtensionTabIdentifier> tabIdentifier, std::optional<WallTime> minTimeStamp) -> (std::optional<Vector<WebKit::WebExtensionMatchedRuleParameters>> matchedRules, std::optional<String> error);

// Event APIs
AddListener(WebKit::WebPageProxyIdentifier identifier, WebKit::WebExtensionEventListenerType type, WebKit::WebExtensionContentWorldType contentWorldType);
Expand Down
6 changes: 6 additions & 0 deletions Source/WebKit/WebKit.xcodeproj/project.pbxproj
Original file line number Diff line number Diff line change
Expand Up @@ -917,6 +917,7 @@
337822442947F679002106BB /* _WKWebExtensionWebNavigationURLFilter.h in Headers */ = {isa = PBXBuildFile; fileRef = 337822422947F679002106BB /* _WKWebExtensionWebNavigationURLFilter.h */; settings = {ATTRIBUTES = (Private, ); }; };
337822472947FBA5002106BB /* WebExtensionUtilities.h in Headers */ = {isa = PBXBuildFile; fileRef = 337822452947FBA4002106BB /* WebExtensionUtilities.h */; };
337822482947FBA5002106BB /* WebExtensionUtilities.mm in Sources */ = {isa = PBXBuildFile; fileRef = 337822462947FBA4002106BB /* WebExtensionUtilities.mm */; settings = {COMPILER_FLAGS = "-fobjc-arc"; }; };
3378F2FD2B1FCA6A00362EF3 /* WebExtensionMatchedRuleParameters.h in Headers */ = {isa = PBXBuildFile; fileRef = 3378F2FB2B1FCA5C00362EF3 /* WebExtensionMatchedRuleParameters.h */; };
33B5A80C2AFD298100A15D40 /* WebExtensionFrameParameters.h in Headers */ = {isa = PBXBuildFile; fileRef = 33B5A80B2AFD298100A15D40 /* WebExtensionFrameParameters.h */; };
33B5A80F2AFD5DE800A15D40 /* WebExtensionContextAPIWebNavigationCocoa.mm in Sources */ = {isa = PBXBuildFile; fileRef = 33B5A80E2AFD5DE800A15D40 /* WebExtensionContextAPIWebNavigationCocoa.mm */; settings = {COMPILER_FLAGS = "-fobjc-arc"; }; };
33F68338293FF6F5005C63C0 /* JSWebExtensionAPIWebNavigationEvent.mm in Sources */ = {isa = PBXBuildFile; fileRef = 33F68336293FF6F5005C63C0 /* JSWebExtensionAPIWebNavigationEvent.mm */; settings = {COMPILER_FLAGS = "-fobjc-arc"; }; };
Expand Down Expand Up @@ -4680,6 +4681,8 @@
337822422947F679002106BB /* _WKWebExtensionWebNavigationURLFilter.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = _WKWebExtensionWebNavigationURLFilter.h; sourceTree = "<group>"; };
337822452947FBA4002106BB /* WebExtensionUtilities.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = WebExtensionUtilities.h; sourceTree = "<group>"; };
337822462947FBA4002106BB /* WebExtensionUtilities.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; path = WebExtensionUtilities.mm; sourceTree = "<group>"; };
3378F2FB2B1FCA5C00362EF3 /* WebExtensionMatchedRuleParameters.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = WebExtensionMatchedRuleParameters.h; sourceTree = "<group>"; };
3378F2FC2B1FCA5C00362EF3 /* WebExtensionMatchedRuleParameters.serialization.in */ = {isa = PBXFileReference; lastKnownFileType = text; path = WebExtensionMatchedRuleParameters.serialization.in; sourceTree = "<group>"; };
33B5A80B2AFD298100A15D40 /* WebExtensionFrameParameters.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = WebExtensionFrameParameters.h; sourceTree = "<group>"; };
33B5A80D2AFD2B2300A15D40 /* WebExtensionFrameParameters.serialization.in */ = {isa = PBXFileReference; lastKnownFileType = text; path = WebExtensionFrameParameters.serialization.in; sourceTree = "<group>"; };
33B5A80E2AFD5DE800A15D40 /* WebExtensionContextAPIWebNavigationCocoa.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; path = WebExtensionContextAPIWebNavigationCocoa.mm; sourceTree = "<group>"; };
Expand Down Expand Up @@ -12717,6 +12720,8 @@
1C4A14C52ABB710E00A1018C /* WebExtensionFrameIdentifier.h */,
33B5A80B2AFD298100A15D40 /* WebExtensionFrameParameters.h */,
33B5A80D2AFD2B2300A15D40 /* WebExtensionFrameParameters.serialization.in */,
3378F2FB2B1FCA5C00362EF3 /* WebExtensionMatchedRuleParameters.h */,
3378F2FC2B1FCA5C00362EF3 /* WebExtensionMatchedRuleParameters.serialization.in */,
1C6BE7A02B0A911B00D01D93 /* WebExtensionMenuItem.serialization.in */,
1CC1A36F2B126AE600373759 /* WebExtensionMenuItemContextParameters.h */,
1C6BE7A42B0A955700D01D93 /* WebExtensionMenuItemContextType.h */,
Expand Down Expand Up @@ -15866,6 +15871,7 @@
B6114A8C293AE06800380B1B /* WebExtensionEventListenerType.h in Headers */,
1C4A14C62ABB710E00A1018C /* WebExtensionFrameIdentifier.h in Headers */,
33B5A80C2AFD298100A15D40 /* WebExtensionFrameParameters.h in Headers */,
3378F2FD2B1FCA6A00362EF3 /* WebExtensionMatchedRuleParameters.h in Headers */,
1C6B84CC2B0D6CF500E885DD /* WebExtensionMenuItem.h in Headers */,
1CC1A3702B126AE600373759 /* WebExtensionMenuItemContextParameters.h in Headers */,
1C6BE7A52B0A955700D01D93 /* WebExtensionMenuItemContextType.h in Headers */,
Expand Down
Loading

0 comments on commit e270f83

Please sign in to comment.