Initial commit

Able to actually block scripts using a plugin, have XPC set up between plugin and
host process. Limited UI support
This commit is contained in:
James Magahern
2020-07-22 19:29:38 -07:00
commit cddc684f54
22 changed files with 1390 additions and 0 deletions

View File

@@ -0,0 +1,23 @@
//
// BrowserView.swift
// SBrowser
//
// Created by James Magahern on 7/21/20.
//
import UIKit
import WebKit
class BrowserView: UIView
{
var webView: WKWebView? {
didSet { addSubview(webView!); setNeedsLayout() }
}
override func layoutSubviews()
{
super.layoutSubviews()
webView?.frame = bounds
}
}

View File

@@ -0,0 +1,63 @@
//
// BrowserViewController.swift
// SBrowser
//
// Created by James Magahern on 7/21/20.
//
import UIKit
class BrowserViewController: UIViewController, SBRProcessBundleBridgeDelegate
{
let bridge = SBRProcessBundleBridge()
let browserView = BrowserView()
private let policyManager = ResourcePolicyManager()
private var blockedScriptOrigins = Set<String>()
private var scriptBlockerButtonItem: UIBarButtonItem
init()
{
scriptBlockerButtonItem = UIBarButtonItem(title: "0", image: nil, primaryAction: UIAction(handler: { action in
// present
}), menu: nil)
super.init(nibName: nil, bundle: nil)
}
required init?(coder: NSCoder) { fatalError("init(coder:) has not been implemented") }
override func loadView()
{
bridge.delegate = self
bridge.policyDataSource = policyManager
browserView.webView = bridge.webView
browserView.webView?.allowsBackForwardNavigationGestures = true
self.view = browserView
}
override func viewDidLoad()
{
let request = URLRequest(url: URL(string: "https://yahoo.com")!)
browserView.webView?.load(request)
navigationItem.rightBarButtonItem = scriptBlockerButtonItem
}
private func updateScriptBlockerButton()
{
scriptBlockerButtonItem.title = "\(blockedScriptOrigins.count)"
}
// MARK: SBRProcessBundleBridgeDelegate
func webProcess(_ bridge: SBRProcessBundleBridge, didBlockScriptResourceFromOrigin origin: String)
{
print("Blocked script resource from origin: \(origin)")
blockedScriptOrigins.formUnion([ origin ])
updateScriptBlockerButton()
}
}

View File

@@ -0,0 +1,37 @@
//
// SBRProcessBundleBridge.h
// SBrowser
//
// Created by James Magahern on 7/22/20.
//
#import <Foundation/Foundation.h>
#import <WebKit/WebKit.h>
NS_ASSUME_NONNULL_BEGIN
@protocol SBRResourceOriginPolicyDataSource <NSObject>
/// Returns a list of origins (e.g., "buzzert.net") for which we are allowed to load script resources from
- (NSSet<NSString *> *)allowedOriginsForScriptResources;
@end
@class SBRProcessBundleBridge;
@protocol SBRProcessBundleBridgeDelegate <NSObject>
- (void)webProcess:(SBRProcessBundleBridge *)bridge didBlockScriptResourceFromOrigin:(NSString *)origin;
@end
@interface SBRProcessBundleBridge : NSObject
@property (nonatomic, readonly) WKWebView *webView;
@property (nonatomic, weak) id<SBRProcessBundleBridgeDelegate> delegate;
@property (nonatomic, weak) id<SBRResourceOriginPolicyDataSource> policyDataSource;
- (void)policyDataSourceDidChange;
@end
NS_ASSUME_NONNULL_END

View File

@@ -0,0 +1,82 @@
//
// 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>
#import <WebKit/WKProcessPoolPrivate.h>
#import <WebKit/WKWebViewPrivate.h>
#import <WebKit/WKWebViewConfigurationPrivate.h>
@interface SBRProcessBundleBridge () <SBRWebProcessDelegate>
@end
@implementation SBRProcessBundleBridge {
WKWebView *_webView;
id<SBRWebProcessProxy> _webProcessProxy;
}
- (WKWebView *)webView
{
if (!_webView) {
// Inject bundle
_WKProcessPoolConfiguration *poolConfiguration = [[_WKProcessPoolConfiguration alloc] init];
NSURL *bundleURL = [[[NSBundle mainBundle] builtInPlugInsURL] URLByAppendingPathComponent:@"SBrowserProcessBundle.bundle"];
[poolConfiguration setInjectedBundleURL:bundleURL];
// Set up process pool
WKProcessPool *processPool = [[WKProcessPool alloc] _initWithConfiguration:poolConfiguration];
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)
_WKRemoteObjectInterface *proxyInterface = [_WKRemoteObjectInterface remoteObjectInterfaceWithProtocol:@protocol(SBRWebProcessProxy)];
_webProcessProxy = [[webView _remoteObjectRegistry] remoteObjectProxyWithInterface:proxyInterface];
// Configure delegate interface (registering us as the web process delegate for the remote process)
_WKRemoteObjectInterface *delegateInterface = [_WKRemoteObjectInterface remoteObjectInterfaceWithProtocol:@protocol(SBRWebProcessDelegate)];
[[webView _remoteObjectRegistry] registerExportedObject:self interface:delegateInterface];
_webView = webView;
}
return _webView;
}
#pragma mark <SBRWebProcessDelegate>
- (void)webProcessDidConnect
{
NSLog(@"SBRProcessBundleBridge: did connect. Saying hello, syncing allowlist");
[_webProcessProxy hello];
[self policyDataSourceDidChange];
}
- (void)webProcessDidLoadScriptWithOrigin:(NSString *)origin
{
[_delegate webProcess:self didBlockScriptResourceFromOrigin:origin];
}
#pragma mark Actions
- (void)policyDataSourceDidChange
{
NSSet<NSString *> *allowedOrigins = [_policyDataSource allowedOriginsForScriptResources];
[_webProcessProxy syncAllowedResourceOrigins:allowedOrigins];
}
@end