// // SBRProcessBundleBridge.m // SBrowser // // Created by James Magahern on 7/22/20. // #import "SBRProcessBundleBridge.h" #import "SBRWebProcessDelegate.h" #import "SBRWebProcessProxy.h" #import #import #import #import #import #import #import #import @interface SBRProcessBundleBridge () @end @implementation SBRProcessBundleBridge { WKWebView *_webView; WKWebViewConfiguration *_webViewConfiguration; WKProcessPool *_processPool; id _webProcessProxy; _WKUserStyleSheet *_darkModeStyleSheet; } - (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; } - (WKWebView *)webView { if (!_webView) { // 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 *allowedOrigins = [[_policyDataSource allowedOriginsForScriptResources] allObjects]; [_processPool _setObject:allowedOrigins forBundleParameter:SBRGetAllowedOriginsKey()]; [_processPool _setObject:@(_allowAllScripts) forBundleParameter:SBRGetAllScriptsAllowedKey()]; WKWebViewConfiguration *configuration = [[WKWebViewConfiguration alloc] init]; configuration.processPool = _processPool; // Instantiate web view WKWebView *webView = [[WKWebView alloc] initWithFrame:CGRectZero configuration:configuration]; // Configure proxy interface (interface to remote web process) _webProcessProxy = [[webView _remoteObjectRegistry] remoteObjectProxyWithInterface:[self _webProcessProxyInterface]]; // Configure delegate interface (registering us as the web process delegate for the remote process) [[webView _remoteObjectRegistry] registerExportedObject:self interface:[self _webProcessDelegateInterface]]; _webView = webView; _webViewConfiguration = configuration; } return _webView; } #pragma mark - (void)webProcessDidConnect { NSLog(@"SBRProcessBundleBridge: did connect. Saying hello, syncing allowlist"); [_webProcessProxy hello]; [self policyDataSourceDidChange]; } - (void)webProcessDidAllowScriptWithOrigin:(NSString *)origin { [[self delegate] webProcess:self didAllowScriptResourceFromOrigin:origin]; } - (void)webProcessDidBlockScriptWithOrigin:(NSString *)origin { [[self delegate] webProcess:self didBlockScriptResourceFromOrigin:origin]; } #pragma mark Actions - (void)policyDataSourceDidChange { NSArray *allowedOrigins = [[_policyDataSource allowedOriginsForScriptResources] allObjects]; [_processPool _setObject:allowedOrigins forBundleParameter:SBRGetAllowedOriginsKey()]; [_webProcessProxy syncAllowedResourceOrigins:allowedOrigins]; } - (void)setAllowAllScripts:(BOOL)allowAllScripts { _allowAllScripts = allowAllScripts; [_processPool _setObject:@(_allowAllScripts) forBundleParameter:SBRGetAllScriptsAllowedKey()]; [_webProcessProxy setAllScriptsAllowed:allowAllScripts]; } - (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]; } } @end