Skip to content

Commit a4be381

Browse files
authored
Merge pull request #1128 from LibertyGlobal/jmanko/mixed_content_whitelist
Implement mixed content whitelist
2 parents ae4b21c + b062a4a commit a4be381

6 files changed

Lines changed: 150 additions & 0 deletions

File tree

Source/WebCore/loader/MixedContentChecker.cpp

Lines changed: 87 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -43,6 +43,8 @@
4343

4444
namespace WebCore {
4545

46+
WTF::Vector<WTF::KeyValuePair<WTF::String, WTF::String>> MixedContentChecker::m_whitelist = {};
47+
4648
// static
4749
bool MixedContentChecker::isMixedContent(SecurityOrigin& securityOrigin, const URL& url)
4850
{
@@ -65,6 +67,11 @@ bool MixedContentChecker::canDisplayInsecureContent(Frame& frame, SecurityOrigin
6567
if (!isMixedContent(securityOrigin, url))
6668
return true;
6769

70+
if (isWhitelisted(securityOrigin.toString(), url.protocolHostAndPort())) {
71+
logWarning(frame, true, "display"_s, url);
72+
return true;
73+
}
74+
6875
if (!frame.document()->contentSecurityPolicy()->allowRunningOrDisplayingInsecureContent(url))
6976
return false;
7077

@@ -88,6 +95,11 @@ bool MixedContentChecker::canRunInsecureContent(Frame& frame, SecurityOrigin& se
8895
if (!isMixedContent(securityOrigin, url))
8996
return true;
9097

98+
if (isWhitelisted(securityOrigin.toString(), url.protocolHostAndPort())) {
99+
logWarning(frame, true, "run"_s, url);
100+
return true;
101+
}
102+
91103
if (!frame.document()->contentSecurityPolicy()->allowRunningOrDisplayingInsecureContent(url))
92104
return false;
93105

@@ -140,4 +152,79 @@ std::optional<String> MixedContentChecker::checkForMixedContentInFrameTree(const
140152
return std::nullopt;
141153
}
142154

155+
bool wildcardMatch(const String& pattern, const String& url)
156+
{
157+
int patternLen = pattern.length();
158+
int patternPos = 0;
159+
int urlLen = url.length();
160+
int urlPos = 0;
161+
int wildcardPos = -1;
162+
int wildcardMatchEnd = 0;
163+
164+
while (urlPos < urlLen) {
165+
if (patternPos < patternLen && pattern[patternPos] == url[urlPos]) {
166+
// characters match
167+
patternPos++;
168+
urlPos++;
169+
} else if (patternPos < patternLen && pattern[patternPos] == '*') {
170+
// mark wildcard position, start matching the rest of the pattern
171+
wildcardPos = patternPos;
172+
wildcardMatchEnd = urlPos;
173+
patternPos++;
174+
} else if (wildcardPos != -1) {
175+
// no match, but we have a wildcard - assume wildcard handles a match to this position,
176+
// revert patternPos to after last *
177+
patternPos = wildcardPos + 1;
178+
wildcardMatchEnd++;
179+
urlPos = wildcardMatchEnd;
180+
} else {
181+
// no match, no wildcard - pattern does not match
182+
return false;
183+
}
184+
}
185+
186+
// url matches so far, and we're at the end of it
187+
// skip any remaining wildcards
188+
while (patternPos < patternLen && pattern[patternPos] == '*') {
189+
patternPos++;
190+
}
191+
// if we're at the end of pattern, that's a match
192+
// otherwise, the remaining part of the pattern can't be matched
193+
return patternPos == patternLen;
194+
}
195+
196+
//static
197+
bool MixedContentChecker::isWhitelisted(const String& origin, const String& domain)
198+
{
199+
for (auto kvPair : m_whitelist) {
200+
if (wildcardMatch(kvPair.key, origin) && wildcardMatch(kvPair.value, domain)) {
201+
return true;
202+
}
203+
}
204+
return false;
205+
}
206+
207+
//static
208+
void MixedContentChecker::addMixedContentWhitelistEntry(const String& origin, const String& domain)
209+
{
210+
MixedContentChecker::m_whitelist.append(makeKeyValuePair(origin, domain));
211+
}
212+
213+
//static
214+
void MixedContentChecker::removeMixedContentWhitelistEntry(const String& origin, const String& domain)
215+
{
216+
for (size_t i = 0; i < MixedContentChecker::m_whitelist.size(); i++) {
217+
if (MixedContentChecker::m_whitelist[i].key == origin && MixedContentChecker::m_whitelist[i].value == domain) {
218+
MixedContentChecker::m_whitelist.remove(i);
219+
break;
220+
}
221+
}
222+
}
223+
224+
//static
225+
void MixedContentChecker::resetMixedContentWhitelist()
226+
{
227+
MixedContentChecker::m_whitelist.clear();
228+
}
229+
143230
} // namespace WebCore

Source/WebCore/loader/MixedContentChecker.h

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,8 @@
3333
#include <optional>
3434
#include <wtf/Forward.h>
3535
#include <wtf/Noncopyable.h>
36+
#include <wtf/KeyValuePair.h>
37+
#include <wtf/Vector.h>
3638

3739
namespace WebCore {
3840

@@ -59,6 +61,14 @@ class MixedContentChecker {
5961
static void checkFormForMixedContent(Frame&, SecurityOrigin&, const URL&);
6062
static bool isMixedContent(SecurityOrigin&, const URL&);
6163
static std::optional<String> checkForMixedContentInFrameTree(const Frame&, const URL&);
64+
65+
static void addMixedContentWhitelistEntry(const String& origin, const String& domain);
66+
static void removeMixedContentWhitelistEntry(const String& origin, const String& domain);
67+
static void resetMixedContentWhitelist();
68+
69+
private:
70+
static bool isWhitelisted(const String& origin, const String& domain);
71+
static WTF::Vector<WTF::KeyValuePair<WTF::String, WTF::String>> m_whitelist;
6272
};
6373

6474
} // namespace WebCore

Source/WebKit/WebProcess/InjectedBundle/API/glib/WebKitWebExtension.cpp

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -280,6 +280,27 @@ void webkit_web_extension_reset_origin_access_whitelists(WebKitWebExtension* ext
280280
extension->priv->bundle->resetOriginAccessAllowLists();
281281
}
282282

283+
void webkit_web_extension_add_mixed_content_whitelist_entry(WebKitWebExtension *extension, const gchar* origin, const gchar* domain)
284+
{
285+
g_return_if_fail(WEBKIT_IS_WEB_EXTENSION(extension));
286+
287+
extension->priv->bundle->addMixedContentWhitelistEntry(String::fromUTF8(origin), String::fromUTF8(domain));
288+
}
289+
290+
void webkit_web_extension_remove_mixed_content_whitelist_entry(WebKitWebExtension *extension, const gchar* origin, const gchar* domain)
291+
{
292+
g_return_if_fail(WEBKIT_IS_WEB_EXTENSION(extension));
293+
294+
extension->priv->bundle->removeMixedContentWhitelistEntry(String::fromUTF8(origin), String::fromUTF8(domain));
295+
}
296+
297+
void webkit_web_extension_reset_mixed_content_whitelist_entry(WebKitWebExtension *extension)
298+
{
299+
g_return_if_fail(WEBKIT_IS_WEB_EXTENSION(extension));
300+
301+
extension->priv->bundle->resetMixedContentWhitelist();
302+
}
303+
283304
/**
284305
* webkit_web_extension_send_message_to_context:
285306
* @extension: a #WebKitWebExtension

Source/WebKit/WebProcess/InjectedBundle/API/wpe/WebKitWebExtension.h

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -101,6 +101,19 @@ webkit_web_extension_remove_origin_access_whitelist_entry (WebKitWebExtension
101101
WEBKIT_API void
102102
webkit_web_extension_reset_origin_access_whitelists (WebKitWebExtension *extension);
103103

104+
WEBKIT_API void
105+
webkit_web_extension_add_mixed_content_whitelist_entry (WebKitWebExtension *extension,
106+
const gchar *origin,
107+
const gchar *domain);
108+
109+
WEBKIT_API void
110+
webkit_web_extension_remove_mixed_content_whitelist_entry (WebKitWebExtension *extension,
111+
const gchar *origin,
112+
const gchar *domain);
113+
114+
WEBKIT_API void
115+
webkit_web_extension_reset_mixed_content_whitelist_entry (WebKitWebExtension *extension);
116+
104117
WEBKIT_API void
105118
webkit_web_extension_send_message_to_context (WebKitWebExtension *extension,
106119
WebKitUserMessage *message,

Source/WebKit/WebProcess/InjectedBundle/InjectedBundle.cpp

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -83,6 +83,8 @@
8383
#include <wtf/ProcessPrivilege.h>
8484
#include <wtf/SystemTracing.h>
8585

86+
#include <WebCore/MixedContentChecker.h>
87+
8688
#if ENABLE(NOTIFICATIONS)
8789
#include "WebNotificationManager.h"
8890
#endif
@@ -171,6 +173,20 @@ void InjectedBundle::resetOriginAccessAllowLists()
171173
WebProcess::singleton().ensureNetworkProcessConnection().connection().send(Messages::NetworkConnectionToWebProcess::ResetOriginAccessAllowLists { }, 0);
172174
}
173175

176+
void InjectedBundle::addMixedContentWhitelistEntry(const String& origin, const String& domain)
177+
{
178+
MixedContentChecker::addMixedContentWhitelistEntry(origin, domain);
179+
}
180+
181+
void InjectedBundle::removeMixedContentWhitelistEntry(const String& origin, const String& domain)
182+
{
183+
MixedContentChecker::removeMixedContentWhitelistEntry(origin, domain);
184+
}
185+
void InjectedBundle::resetMixedContentWhitelist()
186+
{
187+
MixedContentChecker::resetMixedContentWhitelist();
188+
}
189+
174190
void InjectedBundle::setAsynchronousSpellCheckingEnabled(bool enabled)
175191
{
176192
Page::forEachPage([enabled](Page& page) {

Source/WebKit/WebProcess/InjectedBundle/InjectedBundle.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -99,6 +99,9 @@ class InjectedBundle : public API::ObjectImpl<API::Object::Type::Bundle> {
9999
void addOriginAccessAllowListEntry(const String&, const String&, const String&, bool);
100100
void removeOriginAccessAllowListEntry(const String&, const String&, const String&, bool);
101101
void resetOriginAccessAllowLists();
102+
void addMixedContentWhitelistEntry(const String&, const String&);
103+
void removeMixedContentWhitelistEntry(const String&, const String&);
104+
void resetMixedContentWhitelist();
102105
void setAsynchronousSpellCheckingEnabled(bool);
103106
int numberOfPages(WebFrame*, double, double);
104107
int pageNumberForElementById(WebFrame*, const String&, double, double);

0 commit comments

Comments
 (0)