diff --git a/App/Backend/ResourcePolicyManager.swift b/App/Backend/ResourcePolicyManager.swift index 1429ddf..5b16884 100644 --- a/App/Backend/ResourcePolicyManager.swift +++ b/App/Backend/ResourcePolicyManager.swift @@ -30,6 +30,10 @@ class ResourcePolicyManager: NSObject, SBRResourceOriginPolicyDataSource func allowedOriginsForScriptResources() -> Set { allowedOriginSet } + func scriptPolicyTypeByOrigin() -> [String : NSNumber] { + return scriptPolicies.mapValues { NSNumber(integerLiteral: $0.rawValue) } + } + private lazy var scriptPolicies: Dictionary = { if let existingDict = UserDefaults.standard.dictionary(forKey: Self.OriginPoliciesDefaultsKey) as? Dictionary { return existingDict.mapValues { ScriptPolicy.PolicyType(rawValue: $0)! } @@ -53,10 +57,10 @@ class ResourcePolicyManager: NSObject, SBRResourceOriginPolicyDataSource func scriptPolicy(forOrigin origin: String) -> ScriptPolicy { if let policyType = scriptPolicies[origin] { - return ScriptPolicy(policyType: policyType, securityOrigin: origin) + return ScriptPolicy(securityOrigin: origin, policyType: policyType) } - return ScriptPolicy(policyType: .alpha, securityOrigin: origin) + return ScriptPolicy(securityOrigin: origin, policyType: .alpha) } func setScriptPolicyType(_ policyType: ScriptPolicy.PolicyType, forOrigin origin: String) { diff --git a/App/Backend/ScriptPolicy.swift b/App/Backend/ScriptPolicy.swift deleted file mode 100644 index 2c4adf4..0000000 --- a/App/Backend/ScriptPolicy.swift +++ /dev/null @@ -1,84 +0,0 @@ -// -// ScriptPolicy.swift -// App -// -// Created by James Magahern on 9/29/21. -// - -import UIKit - -struct ScriptPolicy: Hashable { - enum PolicyType: Int, CaseIterable { - case alpha - case bravo - case charlie - case delta - case echo - } - - public let policyType: PolicyType - public let securityOrigin: String - - public static func title(forPolicyType type: PolicyType) -> String { - switch type { - case .alpha: return "Alpha" - case .bravo: return "Bravo" - case .charlie: return "Charlie" - case .delta: return "Delta" - case .echo: return "Echo" - } - } - - public static func localizedDescription(forPolicyType type: PolicyType) -> String { - switch type { - case .alpha: - return "All scripts blocked." - case .bravo: - return "Scripts on page are allowed." - case .charlie: - return "Allow scripts from the same security origin." - case .delta: - return "Allow scripts from common and host CDNs." - case .echo: - return "All scripts are allowed." - } - } - - public static func iconRepresentation(forPolicyType type: PolicyType, size: CGSize) -> UIImage? { - let font = UIFont.boldSystemFont(ofSize: size.height - 2) - let attrs: [NSAttributedString.Key : Any] = [ - .font : font, - .foregroundColor: UIColor.white, - ] - - let rect = CGRect(origin: .zero, size: size) - UIGraphicsBeginImageContextWithOptions(size, false, UIScreen.main.scale) - if let _ = UIGraphicsGetCurrentContext() { - let backgroundPath = UIBezierPath.init(roundedRect: rect, cornerRadius: 4.0) - // backgroundPath.usesEvenOddFillRule = true - backgroundPath.fill() - - let character = NSString(string: { () -> String in - switch type { - case .alpha: return "𝝰" - case .bravo: return "𝝱" - case .charlie: return "𝝲" - case .delta: return "𝝳" - case .echo: return "𝝴" - } - }()) - - let charSize = character.size(withAttributes: attrs) - let charRect = CGRect(origin: .init(x: (size.width - charSize.width) / 2 , - y: -(charSize.height - size.height) / 2), - size: charSize) - - character.draw(in: charRect, withAttributes: attrs) - } - - let image = UIGraphicsGetImageFromCurrentImageContext() - UIGraphicsEndImageContext() - - return image - } -} diff --git a/App/Script Policy UI/ScriptPolicyViewController.swift b/App/Script Policy UI/ScriptPolicyViewController.swift index 8e1dacf..186f79e 100644 --- a/App/Script Policy UI/ScriptPolicyViewController.swift +++ b/App/Script Policy UI/ScriptPolicyViewController.swift @@ -7,6 +7,16 @@ import UIKit +extension ScriptPolicy.PolicyType : CaseIterable { + public static var allCases: [ScriptPolicy.PolicyType] = [ + .alpha, + .bravo, + .charlie, + .delta, + .echo + ] +} + class ScriptPolicyViewController: UIViewController, UICollectionViewDelegate { var collectionView: UICollectionView? diff --git a/App/Supporting Files/SBrowser-Bridging-Header.h b/App/Supporting Files/SBrowser-Bridging-Header.h index 2e372a4..e9128ed 100644 --- a/App/Supporting Files/SBrowser-Bridging-Header.h +++ b/App/Supporting Files/SBrowser-Bridging-Header.h @@ -3,6 +3,7 @@ // #import "SBRProcessBundleBridge.h" +#import "SBRScriptPolicy.h" // SPI #import diff --git a/App/Web Process Bundle Bridge/SBRProcessBundleBridge.h b/App/Web Process Bundle Bridge/SBRProcessBundleBridge.h index 8ab36d9..a86d5a2 100644 --- a/App/Web Process Bundle Bridge/SBRProcessBundleBridge.h +++ b/App/Web Process Bundle Bridge/SBRProcessBundleBridge.h @@ -15,6 +15,9 @@ NS_ASSUME_NONNULL_BEGIN /// Returns a list of origins (e.g., "buzzert.net") for which we are allowed to load script resources from - (NSSet *)allowedOriginsForScriptResources; +/// Returns a mapping between origin and SBRScriptOriginPolicyType, encoded as an NSNumber. +- (NSDictionary *)scriptPolicyTypeByOrigin; + @end @class SBRProcessBundleBridge; diff --git a/App/Web Process Bundle Bridge/SBRProcessBundleBridge.m b/App/Web Process Bundle Bridge/SBRProcessBundleBridge.m index 5a379aa..98cf639 100644 --- a/App/Web Process Bundle Bridge/SBRProcessBundleBridge.m +++ b/App/Web Process Bundle Bridge/SBRProcessBundleBridge.m @@ -161,6 +161,10 @@ NSArray *allowedOrigins = [[_policyDataSource allowedOriginsForScriptResources] allObjects]; [_processPool _setObject:allowedOrigins forBundleParameter:SBRGetAllowedOriginsKey()]; [_webProcessProxy syncAllowedResourceOrigins:allowedOrigins]; + + NSDictionary *policyTypes = [_policyDataSource scriptPolicyTypeByOrigin]; + [_processPool _setObject:policyTypes forBundleParameter:SBRGetPolicyTypeByOriginKey()]; + [_webProcessProxy syncPolicyTypes:policyTypes]; } - (void)setAllowAllScripts:(BOOL)allowAllScripts diff --git a/App/Web Process Bundle Bridge/SBRScriptPolicy.h b/App/Web Process Bundle Bridge/SBRScriptPolicy.h new file mode 100644 index 0000000..8fbcb61 --- /dev/null +++ b/App/Web Process Bundle Bridge/SBRScriptPolicy.h @@ -0,0 +1,41 @@ +// +// SBRScriptPolicy.h +// App +// +// Created by James Magahern on 10/15/21. +// + +#import + +NS_ASSUME_NONNULL_BEGIN + +@class UIImage; + +typedef NS_ENUM(NSInteger, SBRScriptOriginPolicyType) { + SBRScriptOriginPolicyTypeAlpha, + SBRScriptOriginPolicyTypeBravo, + SBRScriptOriginPolicyTypeCharlie, + SBRScriptOriginPolicyTypeDelta, + SBRScriptOriginPolicyTypeEcho, +} NS_SWIFT_NAME(ScriptPolicy.PolicyType); + +NS_SWIFT_NAME(ScriptPolicy) +@interface SBRScriptPolicy : NSObject +@property (nonatomic, copy) NSString *origin; +@property (nonatomic, readwrite) SBRScriptOriginPolicyType policyType; + ++ (NSString *)titleForPolicyType:(SBRScriptOriginPolicyType)policyType + NS_SWIFT_NAME(title(forPolicyType:)); + ++ (NSString *)localizedDescriptionForPolicyType:(SBRScriptOriginPolicyType)policyType + NS_SWIFT_NAME(localizedDescription(forPolicyType:)); + ++ (UIImage *)iconRepresentationForPolicyType:(SBRScriptOriginPolicyType)policyType withSize:(CGSize)size + NS_SWIFT_NAME(iconRepresentation(forPolicyType:size:)); + +- (instancetype)initWithSecurityOrigin:(NSString *)origin policyType:(SBRScriptOriginPolicyType)policyType; + +- (instancetype)init NS_UNAVAILABLE; +@end + +NS_ASSUME_NONNULL_END diff --git a/App/Web Process Bundle Bridge/SBRScriptPolicy.m b/App/Web Process Bundle Bridge/SBRScriptPolicy.m new file mode 100644 index 0000000..a6db8ab --- /dev/null +++ b/App/Web Process Bundle Bridge/SBRScriptPolicy.m @@ -0,0 +1,121 @@ +// +// SBRScriptPolicy.m +// App +// +// Created by James Magahern on 10/15/21. +// + +#import "SBRScriptPolicy.h" + +// For icon drawing +#import + +@implementation SBRScriptPolicy + ++ (NSString *)titleForPolicyType:(SBRScriptOriginPolicyType)policyType +{ + switch (policyType) { + case SBRScriptOriginPolicyTypeAlpha: + return @"Alpha"; + case SBRScriptOriginPolicyTypeBravo: + return @"Bravo"; + case SBRScriptOriginPolicyTypeCharlie: + return @"Charlie"; + case SBRScriptOriginPolicyTypeDelta: + return @"Delta"; + case SBRScriptOriginPolicyTypeEcho: + return @"Echo"; + } +} + ++ (NSString *)localizedDescriptionForPolicyType:(SBRScriptOriginPolicyType)policyType +{ + switch (policyType) { + case SBRScriptOriginPolicyTypeAlpha: + return @"All scripts blocked."; + case SBRScriptOriginPolicyTypeBravo: + return @"Scripts on page are allowed."; + case SBRScriptOriginPolicyTypeCharlie: + return @"Allow scripts from the same security origin."; + case SBRScriptOriginPolicyTypeDelta: + return @"Allow scripts from common and host CDNs."; + case SBRScriptOriginPolicyTypeEcho: + return @"All scripts are allowed."; + } +} + ++ (UIImage *)iconRepresentationForPolicyType:(SBRScriptOriginPolicyType)policyType withSize:(CGSize)size +{ + UIFont *font = [UIFont boldSystemFontOfSize:size.height - 2]; + NSDictionary *attrs = @{ + NSFontAttributeName : font, + NSForegroundColorAttributeName : [UIColor whiteColor] + }; + + const CGRect rect = (CGRect) { .origin = CGPointZero, .size = size }; + UIGraphicsBeginImageContextWithOptions(size, NO, UIScreen.mainScreen.scale); + + UIBezierPath *backgroundPath = [UIBezierPath bezierPathWithRoundedRect:rect cornerRadius:4.0]; + [backgroundPath fill]; + + NSString *character = @""; + switch (policyType) { + case SBRScriptOriginPolicyTypeAlpha: + character = @"𝝰"; break; + case SBRScriptOriginPolicyTypeBravo: + character = @"𝝱"; break; + case SBRScriptOriginPolicyTypeCharlie: + character = @"𝝲"; break; + case SBRScriptOriginPolicyTypeDelta: + character = @"𝝳"; break; + case SBRScriptOriginPolicyTypeEcho: + character = @"𝝴"; break; + } + + const CGSize charSize = [character sizeWithAttributes:attrs]; + const CGRect charRect = (CGRect) { + .origin = (CGPoint) { + .x = (size.width - charSize.width) / 2, + .y = -(charSize.height - size.height) / 2, + }, + + .size = charSize + }; + + [character drawInRect:charRect withAttributes:attrs]; + + UIImage *image = UIGraphicsGetImageFromCurrentImageContext(); + UIGraphicsEndImageContext(); + + return image; +} + ++ (BOOL)supportsSecureCoding +{ + return YES; +} + +- (instancetype)initWithSecurityOrigin:(NSString *)origin policyType:(SBRScriptOriginPolicyType)policyType +{ + if (self = [super init]) { + _origin = [origin copy]; + _policyType = policyType; + } + + return self; +} + +- (instancetype)initWithCoder:(NSCoder *)coder +{ + NSString *origin = [coder decodeObjectForKey:@"origin"]; + NSNumber *policyTypeNumber = [coder decodeObjectForKey:@"policyType"]; + return [self initWithSecurityOrigin:origin policyType:[policyTypeNumber integerValue]]; +} + +- (void)encodeWithCoder:(NSCoder *)coder +{ + [coder encodeObject:_origin forKey:@"origin"]; + [coder encodeObject:[NSNumber numberWithInteger:_policyType] forKey:@"policyType"]; +} + +@end diff --git a/SBrowser.xcodeproj/project.pbxproj b/SBrowser.xcodeproj/project.pbxproj index 4f9f5ee..8e88dd7 100644 --- a/SBrowser.xcodeproj/project.pbxproj +++ b/SBrowser.xcodeproj/project.pbxproj @@ -43,11 +43,11 @@ CD01D5AB254A206D00189CDC /* TabBarViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = CD01D5AA254A206D00189CDC /* TabBarViewController.swift */; }; CD16844D269E709400B8F8A5 /* Box.swift in Sources */ = {isa = PBXBuildFile; fileRef = CD16844C269E709400B8F8A5 /* Box.swift */; }; CD19576D268BE95900E8089B /* GenericContentView.swift in Sources */ = {isa = PBXBuildFile; fileRef = CD19576C268BE95900E8089B /* GenericContentView.swift */; }; + CD361CF6271A3718006E9CA5 /* SBRScriptPolicy.m in Sources */ = {isa = PBXBuildFile; fileRef = CD361CF5271A3718006E9CA5 /* SBRScriptPolicy.m */; }; CD470C4225DE056600AFBE0E /* BrowserViewController+WebKitDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = CD470C4125DE056600AFBE0E /* BrowserViewController+WebKitDelegate.swift */; }; CD470C4425DE070400AFBE0E /* BrowserViewController+Keyboard.swift in Sources */ = {isa = PBXBuildFile; fileRef = CD470C4325DE070400AFBE0E /* BrowserViewController+Keyboard.swift */; }; CD7313E22705349700053347 /* ScriptPolicyViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = CD7313E12705349700053347 /* ScriptPolicyViewController.swift */; }; CD7313E4270534B800053347 /* ScriptPolicyViewControllerDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = CD7313E3270534B800053347 /* ScriptPolicyViewControllerDelegate.swift */; }; - CD7313E62705353500053347 /* ScriptPolicy.swift in Sources */ = {isa = PBXBuildFile; fileRef = CD7313E52705353500053347 /* ScriptPolicy.swift */; }; CD7A7E9D2686A9A500E20BA3 /* SettingsViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = CD7A7E9C2686A9A500E20BA3 /* SettingsViewController.swift */; }; CD7A7E9F2686B29100E20BA3 /* GeneralSettingsViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = CD7A7E9E2686B29100E20BA3 /* GeneralSettingsViewController.swift */; }; CD7A7EA12686B2E600E20BA3 /* RedirectRulesSettingsViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = CD7A7EA02686B2E600E20BA3 /* RedirectRulesSettingsViewController.swift */; }; @@ -145,11 +145,12 @@ CD01D5AA254A206D00189CDC /* TabBarViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TabBarViewController.swift; sourceTree = ""; }; CD16844C269E709400B8F8A5 /* Box.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Box.swift; sourceTree = ""; }; CD19576C268BE95900E8089B /* GenericContentView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = GenericContentView.swift; sourceTree = ""; }; + CD361CF4271A3718006E9CA5 /* SBRScriptPolicy.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = SBRScriptPolicy.h; sourceTree = ""; }; + CD361CF5271A3718006E9CA5 /* SBRScriptPolicy.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = SBRScriptPolicy.m; sourceTree = ""; }; CD470C4125DE056600AFBE0E /* BrowserViewController+WebKitDelegate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "BrowserViewController+WebKitDelegate.swift"; sourceTree = ""; }; CD470C4325DE070400AFBE0E /* BrowserViewController+Keyboard.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "BrowserViewController+Keyboard.swift"; sourceTree = ""; }; CD7313E12705349700053347 /* ScriptPolicyViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ScriptPolicyViewController.swift; sourceTree = ""; }; CD7313E3270534B800053347 /* ScriptPolicyViewControllerDelegate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ScriptPolicyViewControllerDelegate.swift; sourceTree = ""; }; - CD7313E52705353500053347 /* ScriptPolicy.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ScriptPolicy.swift; sourceTree = ""; }; CD7A7E9C2686A9A500E20BA3 /* SettingsViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SettingsViewController.swift; sourceTree = ""; }; CD7A7E9E2686B29100E20BA3 /* GeneralSettingsViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = GeneralSettingsViewController.swift; sourceTree = ""; }; CD7A7EA02686B2E600E20BA3 /* RedirectRulesSettingsViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RedirectRulesSettingsViewController.swift; sourceTree = ""; }; @@ -327,7 +328,6 @@ CD853BD224E77BEF00D2BDCC /* History */, 1ADFF4AD24C8ED32006DC7AE /* ResourcePolicyManager.swift */, 1AD3103C252541E600A4A952 /* PersonalRedirectRules.swift */, - CD7313E52705353500053347 /* ScriptPolicy.swift */, ); path = Backend; sourceTree = ""; @@ -355,6 +355,8 @@ 1ADFF4AF24C92E2F006DC7AE /* Web Process Bundle Bridge */ = { isa = PBXGroup; children = ( + CD361CF4271A3718006E9CA5 /* SBRScriptPolicy.h */, + CD361CF5271A3718006E9CA5 /* SBRScriptPolicy.m */, 1ADFF48B24C8C176006DC7AE /* SBRProcessBundleBridge.h */, 1ADFF48C24C8C176006DC7AE /* SBRProcessBundleBridge.m */, ); @@ -577,12 +579,12 @@ CDD0522125F8023700DD1771 /* Settings.swift in Sources */, 1AD31040252545BF00A4A952 /* FindOnPageView.swift in Sources */, CD470C4225DE056600AFBE0E /* BrowserViewController+WebKitDelegate.swift in Sources */, - CD7313E62705353500053347 /* ScriptPolicy.swift in Sources */, CDEDD8AA25D62ADB00862605 /* UITraitCollection+MacLike.swift in Sources */, CD7A8919251989C90075991E /* UIKeyCommand+ConvInit.swift in Sources */, 1ADFF4C724CA6DEB006DC7AE /* UIEdgeInsets+Layout.swift in Sources */, 1ADFF4AE24C8ED32006DC7AE /* ResourcePolicyManager.swift in Sources */, 1ADFF47424C7DE9C006DC7AE /* BrowserViewController.swift in Sources */, + CD361CF6271A3718006E9CA5 /* SBRScriptPolicy.m in Sources */, CDCE2668251AAA9A007FE92A /* FontSizeAdjustView.swift in Sources */, CD01D5A5254A10BB00189CDC /* TabBarView.swift in Sources */, 1A03810D24E71CA700826501 /* ToolbarView.swift in Sources */, diff --git a/SBrowserProcessBundle/SBRProcessPlugin.m b/SBrowserProcessBundle/SBRProcessPlugin.m index 2bac957..c1baf0d 100644 --- a/SBrowserProcessBundle/SBRProcessPlugin.m +++ b/SBrowserProcessBundle/SBRProcessPlugin.m @@ -19,8 +19,10 @@ @interface SBRProcessPlugin () @property (nonatomic, strong) id processDelegate; -@property (nonatomic, strong) NSMutableSet *allowedResourceOrigins; + @property (nonatomic, assign) BOOL allScriptsAllowed; +@property (nonatomic, strong) NSMutableSet *allowedResourceOrigins; +@property (nonatomic, strong) NSDictionary *policyTypeByOrigin; @end @implementation SBRProcessPlugin @@ -43,6 +45,11 @@ _allowedResourceOrigins = [NSMutableSet setWithArray:allowedOrigins]; } +- (void)syncPolicyTypes:(NSDictionary *)policyTypes +{ + _policyTypeByOrigin = policyTypes; +} + - (void)setAllScriptsAllowed:(BOOL)allScriptsAllowed { _allScriptsAllowed = allScriptsAllowed; diff --git a/SBrowserProcessBundle/SBRWebProcessProxy.h b/SBrowserProcessBundle/SBRWebProcessProxy.h index f39bf8a..341f0cc 100644 --- a/SBrowserProcessBundle/SBRWebProcessProxy.h +++ b/SBrowserProcessBundle/SBRWebProcessProxy.h @@ -15,10 +15,15 @@ static inline NSString* SBRGetAllScriptsAllowedKey() { return @"allScriptsAllowed"; } +static inline NSString* SBRGetPolicyTypeByOriginKey() { + return @"policyTypeByOrigin"; +} + @protocol SBRWebProcessProxy - (void)hello; -- (void)syncAllowedResourceOrigins:(NSArray *)allowedOrigins; - (void)setAllScriptsAllowed:(BOOL)allowed; +- (void)syncAllowedResourceOrigins:(NSArray *)allowedOrigins; +- (void)syncPolicyTypes:(NSDictionary *)policyTypes; @end