2020-07-22 19:29:38 -07:00
|
|
|
//
|
|
|
|
|
// SBRProcessBundleBridge.m
|
|
|
|
|
// SBrowser
|
|
|
|
|
//
|
|
|
|
|
// Created by James Magahern on 7/22/20.
|
|
|
|
|
//
|
|
|
|
|
|
|
|
|
|
#import "SBRProcessBundleBridge.h"
|
|
|
|
|
|
|
|
|
|
#import "SBRWebProcessDelegate.h"
|
|
|
|
|
#import "SBRWebProcessProxy.h"
|
|
|
|
|
|
|
|
|
|
#import <WebKit/_WKRemoteObjectInterface.h>
|
|
|
|
|
#import <WebKit/_WKRemoteObjectRegistry.h>
|
|
|
|
|
#import <WebKit/_WKProcessPoolConfiguration.h>
|
2020-07-29 18:17:22 -07:00
|
|
|
#import <WebKit/_WKUserStyleSheet.h>
|
2020-07-22 19:29:38 -07:00
|
|
|
|
|
|
|
|
#import <WebKit/WKProcessPoolPrivate.h>
|
|
|
|
|
#import <WebKit/WKWebViewPrivate.h>
|
|
|
|
|
#import <WebKit/WKWebViewConfigurationPrivate.h>
|
2020-07-29 18:17:22 -07:00
|
|
|
#import <WebKit/WKUserContentControllerPrivate.h>
|
2020-07-22 19:29:38 -07:00
|
|
|
|
|
|
|
|
@interface SBRProcessBundleBridge () <SBRWebProcessDelegate>
|
|
|
|
|
|
|
|
|
|
@end
|
|
|
|
|
|
|
|
|
|
@implementation SBRProcessBundleBridge {
|
2020-07-29 18:17:22 -07:00
|
|
|
WKWebView *_webView;
|
|
|
|
|
WKWebViewConfiguration *_webViewConfiguration;
|
2020-07-29 18:58:31 -07:00
|
|
|
WKProcessPool *_processPool;
|
2020-07-22 19:29:38 -07:00
|
|
|
id<SBRWebProcessProxy> _webProcessProxy;
|
2020-07-29 18:17:22 -07:00
|
|
|
|
|
|
|
|
_WKUserStyleSheet *_darkModeStyleSheet;
|
2021-02-15 22:34:05 -08:00
|
|
|
WKUserScript *_readabilityScript;
|
2021-02-26 17:43:53 -08:00
|
|
|
|
|
|
|
|
NSArray<WKUserScript *> *_userScripts;
|
2020-07-22 19:29:38 -07:00
|
|
|
}
|
|
|
|
|
|
2020-07-30 23:54:20 -07:00
|
|
|
- (void)tearDown
|
|
|
|
|
{
|
|
|
|
|
[[_webView _remoteObjectRegistry] unregisterExportedObject:self interface:[self _webProcessDelegateInterface]];
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
- (_WKRemoteObjectInterface *)_webProcessDelegateInterface
|
|
|
|
|
{
|
|
|
|
|
static dispatch_once_t onceToken;
|
|
|
|
|
static _WKRemoteObjectInterface *interface = nil;
|
|
|
|
|
dispatch_once(&onceToken, ^{
|
|
|
|
|
interface = [_WKRemoteObjectInterface remoteObjectInterfaceWithProtocol:@protocol(SBRWebProcessDelegate)];
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
return interface;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
- (_WKRemoteObjectInterface *)_webProcessProxyInterface
|
|
|
|
|
{
|
|
|
|
|
static dispatch_once_t onceToken;
|
|
|
|
|
static _WKRemoteObjectInterface *interface = nil;
|
|
|
|
|
dispatch_once(&onceToken, ^{
|
|
|
|
|
interface = [_WKRemoteObjectInterface remoteObjectInterfaceWithProtocol:@protocol(SBRWebProcessProxy)];
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
return interface;
|
|
|
|
|
}
|
|
|
|
|
|
2020-09-24 16:36:31 -07:00
|
|
|
- (instancetype)initWithWebViewConfiguration:(WKWebViewConfiguration *)webViewConfiguration
|
2020-07-22 19:29:38 -07:00
|
|
|
{
|
2020-09-24 16:36:31 -07:00
|
|
|
self = [super init];
|
|
|
|
|
if (self) {
|
|
|
|
|
if (!webViewConfiguration) {
|
|
|
|
|
webViewConfiguration = [[WKWebViewConfiguration alloc] init];
|
|
|
|
|
|
|
|
|
|
// Inject bundle
|
|
|
|
|
_WKProcessPoolConfiguration *poolConfiguration = [[_WKProcessPoolConfiguration alloc] init];
|
|
|
|
|
NSURL *bundleURL = [[[NSBundle mainBundle] builtInPlugInsURL] URLByAppendingPathComponent:@"SBrowserProcessBundle.bundle"];
|
|
|
|
|
|
|
|
|
|
// Make sure it exists. Bail if otherwise.
|
|
|
|
|
NSBundle *pluginBundle = [NSBundle bundleWithURL:bundleURL];
|
|
|
|
|
NSAssert(pluginBundle != nil, @"Attix process bundle not found at %@", bundleURL.path);
|
|
|
|
|
|
|
|
|
|
[poolConfiguration setInjectedBundleURL:bundleURL];
|
|
|
|
|
|
|
|
|
|
// Set up process pool
|
|
|
|
|
_processPool = [[WKProcessPool alloc] _initWithConfiguration:poolConfiguration];
|
|
|
|
|
|
|
|
|
|
// Initialize allowed origins now
|
|
|
|
|
NSArray<NSString *> *allowedOrigins = [[_policyDataSource allowedOriginsForScriptResources] allObjects];
|
|
|
|
|
[_processPool _setObject:allowedOrigins forBundleParameter:SBRGetAllowedOriginsKey()];
|
|
|
|
|
[_processPool _setObject:@(_allowAllScripts) forBundleParameter:SBRGetAllScriptsAllowedKey()];
|
|
|
|
|
|
|
|
|
|
webViewConfiguration.processPool = _processPool;
|
|
|
|
|
}
|
2020-08-14 17:40:01 -07:00
|
|
|
|
2020-09-24 16:36:31 -07:00
|
|
|
_webViewConfiguration = webViewConfiguration;
|
2020-07-22 19:29:38 -07:00
|
|
|
|
2021-02-26 17:43:53 -08:00
|
|
|
// User scripts
|
|
|
|
|
WKUserContentController *userContentController = [_webViewConfiguration userContentController];
|
|
|
|
|
for (WKUserScript *script in [self _userScripts]) {
|
|
|
|
|
[userContentController addUserScript:script];
|
|
|
|
|
}
|
|
|
|
|
|
2020-07-22 19:29:38 -07:00
|
|
|
// Instantiate web view
|
2020-09-24 16:36:31 -07:00
|
|
|
WKWebView *webView = [[WKWebView alloc] initWithFrame:CGRectZero configuration:webViewConfiguration];
|
2020-07-22 19:29:38 -07:00
|
|
|
|
|
|
|
|
// Configure proxy interface (interface to remote web process)
|
2020-07-30 23:54:20 -07:00
|
|
|
_webProcessProxy = [[webView _remoteObjectRegistry] remoteObjectProxyWithInterface:[self _webProcessProxyInterface]];
|
2020-07-22 19:29:38 -07:00
|
|
|
|
|
|
|
|
// Configure delegate interface (registering us as the web process delegate for the remote process)
|
2020-07-30 23:54:20 -07:00
|
|
|
[[webView _remoteObjectRegistry] registerExportedObject:self interface:[self _webProcessDelegateInterface]];
|
2020-07-22 19:29:38 -07:00
|
|
|
|
|
|
|
|
_webView = webView;
|
|
|
|
|
}
|
|
|
|
|
|
2020-09-24 16:36:31 -07:00
|
|
|
return self;
|
2020-07-22 19:29:38 -07:00
|
|
|
}
|
|
|
|
|
|
2021-02-26 17:43:53 -08:00
|
|
|
- (WKUserScript *)_loadScriptForResource:(NSString *)resourceName withExtension:(NSString *)extension
|
|
|
|
|
{
|
|
|
|
|
NSURL *url = [[NSBundle mainBundle] URLForResource:resourceName withExtension:extension];
|
|
|
|
|
NSString *source = [NSString stringWithContentsOfURL:url encoding:NSUTF8StringEncoding error:nil];
|
|
|
|
|
|
|
|
|
|
return [[WKUserScript alloc] initWithSource:source injectionTime:WKUserScriptInjectionTimeAtDocumentEnd forMainFrameOnly:YES];
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
- (NSArray<WKUserScript *> *)_userScripts
|
|
|
|
|
{
|
|
|
|
|
if (!_userScripts) {
|
|
|
|
|
_userScripts = @[
|
|
|
|
|
[self _loadScriptForResource:@"Tagger" withExtension:@"js"],
|
|
|
|
|
];
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return _userScripts;
|
|
|
|
|
}
|
|
|
|
|
|
2020-07-22 19:29:38 -07:00
|
|
|
#pragma mark <SBRWebProcessDelegate>
|
|
|
|
|
|
|
|
|
|
- (void)webProcessDidConnect
|
|
|
|
|
{
|
|
|
|
|
NSLog(@"SBRProcessBundleBridge: did connect. Saying hello, syncing allowlist");
|
2020-09-22 12:30:09 -07:00
|
|
|
_webContentProcessConnected = YES;
|
|
|
|
|
|
2020-07-22 19:29:38 -07:00
|
|
|
[_webProcessProxy hello];
|
|
|
|
|
[self policyDataSourceDidChange];
|
|
|
|
|
}
|
|
|
|
|
|
2020-07-29 18:58:31 -07:00
|
|
|
- (void)webProcessDidAllowScriptWithOrigin:(NSString *)origin
|
2020-07-22 19:29:38 -07:00
|
|
|
{
|
2020-07-29 18:58:31 -07:00
|
|
|
[[self delegate] webProcess:self didAllowScriptResourceFromOrigin:origin];
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
- (void)webProcessDidBlockScriptWithOrigin:(NSString *)origin
|
|
|
|
|
{
|
|
|
|
|
[[self delegate] webProcess:self didBlockScriptResourceFromOrigin:origin];
|
2020-07-22 19:29:38 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
#pragma mark Actions
|
|
|
|
|
|
|
|
|
|
- (void)policyDataSourceDidChange
|
|
|
|
|
{
|
2020-07-24 19:26:35 -07:00
|
|
|
NSArray<NSString *> *allowedOrigins = [[_policyDataSource allowedOriginsForScriptResources] allObjects];
|
2020-07-29 18:58:31 -07:00
|
|
|
[_processPool _setObject:allowedOrigins forBundleParameter:SBRGetAllowedOriginsKey()];
|
2020-07-22 19:29:38 -07:00
|
|
|
[_webProcessProxy syncAllowedResourceOrigins:allowedOrigins];
|
2021-10-21 11:05:40 -07:00
|
|
|
|
|
|
|
|
NSDictionary<NSString *, NSNumber *> *policyTypes = [_policyDataSource scriptPolicyTypeByOrigin];
|
|
|
|
|
[_processPool _setObject:policyTypes forBundleParameter:SBRGetPolicyTypeByOriginKey()];
|
|
|
|
|
[_webProcessProxy syncPolicyTypes:policyTypes];
|
2020-07-22 19:29:38 -07:00
|
|
|
}
|
|
|
|
|
|
2020-07-29 17:46:53 -07:00
|
|
|
- (void)setAllowAllScripts:(BOOL)allowAllScripts
|
|
|
|
|
{
|
2020-07-29 18:58:31 -07:00
|
|
|
_allowAllScripts = allowAllScripts;
|
|
|
|
|
[_processPool _setObject:@(_allowAllScripts) forBundleParameter:SBRGetAllScriptsAllowedKey()];
|
2020-07-29 17:46:53 -07:00
|
|
|
[_webProcessProxy setAllScriptsAllowed:allowAllScripts];
|
|
|
|
|
}
|
|
|
|
|
|
2020-07-29 18:17:22 -07:00
|
|
|
- (void)setDarkModeEnabled:(BOOL)darkModeEnabled
|
|
|
|
|
{
|
|
|
|
|
_darkModeEnabled = darkModeEnabled;
|
|
|
|
|
|
|
|
|
|
WKUserContentController *userContentController = [_webViewConfiguration userContentController];
|
|
|
|
|
|
|
|
|
|
if (darkModeEnabled) {
|
|
|
|
|
if (!_darkModeStyleSheet) {
|
|
|
|
|
NSURL *styleSheetURL = [[NSBundle mainBundle] URLForResource:@"darkmode" withExtension:@"css"];
|
|
|
|
|
NSString *styleSheetSource = [NSString stringWithContentsOfURL:styleSheetURL encoding:NSUTF8StringEncoding error:nil];
|
|
|
|
|
_darkModeStyleSheet = [[_WKUserStyleSheet alloc] initWithSource:styleSheetSource forMainFrameOnly:NO];
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
[userContentController _addUserStyleSheet:_darkModeStyleSheet];
|
|
|
|
|
} else if (_darkModeStyleSheet) {
|
|
|
|
|
[userContentController _removeUserStyleSheet:_darkModeStyleSheet];
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2021-02-15 22:34:05 -08:00
|
|
|
|
|
|
|
|
- (void)parseDocumentForReaderMode:(void (^)(NSString * _Nonnull))completionBlock
|
|
|
|
|
{
|
|
|
|
|
WKUserContentController *userContentController = [_webViewConfiguration userContentController];
|
|
|
|
|
|
|
|
|
|
if (!_readabilityScript) {
|
2021-02-26 17:43:53 -08:00
|
|
|
_readabilityScript = [self _loadScriptForResource:@"Readability" withExtension:@"js"];
|
2021-02-15 22:34:05 -08:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
[userContentController _addUserScriptImmediately:_readabilityScript];
|
|
|
|
|
|
|
|
|
|
NSString *script = @""
|
|
|
|
|
"var documentClone = document.cloneNode(true);"
|
|
|
|
|
"var article = new Readability(documentClone).parse();"
|
|
|
|
|
"article.content";
|
|
|
|
|
|
|
|
|
|
[_webView evaluateJavaScript:script completionHandler:^(NSString *result, NSError * _Nullable error) {
|
|
|
|
|
if (error != nil) {
|
|
|
|
|
NSLog(@"Bridge: Readability error: %@", error.localizedDescription);
|
|
|
|
|
} else {
|
|
|
|
|
completionBlock(result);
|
|
|
|
|
}
|
|
|
|
|
}];
|
|
|
|
|
}
|
|
|
|
|
|
2020-07-22 19:29:38 -07:00
|
|
|
@end
|