iOS web browser with a focus on security and privacy
at master 261 lines 10 kB view raw
1/* 2 * Endless 3 * Copyright (c) 2014-2015 joshua stein <jcs@jcs.org> 4 * 5 * See LICENSE file for redistribution terms. 6 */ 7 8#import "AppDelegate.h" 9#import "Bookmark.h" 10#import "CookieController.h" 11#import "HostSettings.h" 12#import "HostSettingsController.h" 13#import "IASKAppSettingsViewController.h" 14#import "HTTPSEverywhereRuleController.h" 15#import "URLBlockerRuleController.h" 16#import "WebViewMenuController.h" 17 18#import "OnePasswordExtension.h" 19#import "TUSafariActivity.h" 20 21@implementation WebViewMenuController { 22 AppDelegate *appDelegate; 23 IASKAppSettingsViewController *appSettingsViewController; 24 NSMutableArray *buttons; 25} 26 27NSString * const FUNC = @"F"; 28NSString * const LABEL = @"L"; 29 30- (void)viewDidLoad 31{ 32 [super viewDidLoad]; 33 34 appDelegate = (AppDelegate *)[[UIApplication sharedApplication] delegate]; 35 36 buttons = [[NSMutableArray alloc] initWithCapacity:10]; 37 38 [buttons addObject:@{ FUNC : @"menuRefresh", LABEL : NSLocalizedString(@"Refresh", nil) }]; 39 40 /* no point in showing this if the user doesn't have a password manager installed */ 41 if ([[UIApplication sharedApplication] canOpenURL:[NSURL URLWithString:@"bitwarden://"]]) 42 [buttons addObject:@{ FUNC : @"menuOnePassword", LABEL : NSLocalizedString(@"Fill with Bitwarden", nil) }]; 43 else if ([[UIApplication sharedApplication] canOpenURL:[NSURL URLWithString:@"onepassword://"]]) 44 [buttons addObject:@{ FUNC : @"menuOnePassword", LABEL : NSLocalizedString(@"Fill with 1Password", nil) }]; 45 else if ([[UIApplication sharedApplication] canOpenURL:[NSURL URLWithString:@"org-appextension-feature-password-management://"]]) 46 [buttons addObject:@{ FUNC : @"menuOnePassword", LABEL : NSLocalizedString(@"Password Manager", nil) }]; 47 48 [buttons addObject:@{ FUNC : @"menuAddOrManageBookmarks", LABEL : NSLocalizedString(@"Manage Bookmarks", nil) }]; 49 [buttons addObject:@{ FUNC : @"menuShare", LABEL : NSLocalizedString(@"Share URL", nil) }]; 50 [buttons addObject:@{ FUNC : @"menuURLBlocker", LABEL : NSLocalizedString(@"URL Blocker", nil) }]; 51 [buttons addObject:@{ FUNC : @"menuHTTPSEverywhere", LABEL : NSLocalizedString(@"HTTPS Everywhere", nil) }]; 52 [buttons addObject:@{ FUNC : @"menuHostSettings", LABEL : NSLocalizedString(@"Host Settings", nil) }]; 53 [buttons addObject:@{ FUNC : @"menuSettings", LABEL : NSLocalizedString(@"Global Settings", nil) }]; 54 55 [self.view setBackgroundColor:[UIColor clearColor]]; 56 [self.tableView setSeparatorInset:UIEdgeInsetsZero]; 57 58 if ([[appDelegate webViewController] darkInterface]) 59 [self.tableView setSeparatorColor:[UIColor colorWithRed:0.3 green:0.3 blue:0.3 alpha:0.75]]; 60} 61 62- (CGSize)preferredContentSize 63{ 64 return CGSizeMake(160, [self tableView:self.tableView heightForRowAtIndexPath:[[NSIndexPath alloc] init]] * [buttons count]); 65} 66 67#pragma mark - Table view data source 68 69- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section 70{ 71 return [buttons count]; 72} 73 74-(void)tableView:(UITableView *)tableView willDisplayCell:(UITableViewCell *)cell forRowAtIndexPath:(NSIndexPath *)indexPath 75{ 76 if ([cell respondsToSelector:@selector(setSeparatorInset:)]) 77 [cell setSeparatorInset:UIEdgeInsetsZero]; 78 79 if ([cell respondsToSelector:@selector(setPreservesSuperviewLayoutMargins:)]) 80 [cell setPreservesSuperviewLayoutMargins:NO]; 81 82 if ([cell respondsToSelector:@selector(setLayoutMargins:)]) 83 [cell setLayoutMargins:UIEdgeInsetsZero]; 84} 85 86- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath 87{ 88 UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:@"button"]; 89 if (cell == nil) 90 cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleSubtitle reuseIdentifier:@"button"]; 91 92 NSDictionary *button = [buttons objectAtIndex:[indexPath row]]; 93 94 cell.backgroundColor = [UIColor clearColor]; 95 cell.textLabel.font = [UIFont systemFontOfSize:13]; 96 cell.textLabel.text = [button objectForKey:LABEL]; 97 cell.detailTextLabel.text = nil; 98 cell.detailTextLabel.font = [UIFont systemFontOfSize:11]; 99 100 if ([[appDelegate webViewController] darkInterface]) { 101 cell.textLabel.textColor = [UIColor colorWithRed:0.8 green:0.8 blue:0.8 alpha:1.0]; 102 cell.detailTextLabel.textColor = [UIColor grayColor]; 103 } 104 105 BOOL haveURL = ([[[appDelegate webViewController] curWebViewTab] url] != nil); 106 107 NSString *func = [button objectForKey:FUNC]; 108 if ([func isEqualToString:@"menuAddOrManageBookmarks"]) { 109 if (haveURL && [Bookmark isURLBookmarked:[[[appDelegate webViewController] curWebViewTab] url]]) { 110 cell.textLabel.text = NSLocalizedString(@"Bookmarks", nil); 111 cell.detailTextLabel.text = NSLocalizedString(@"Page bookmarked", nil); 112 } 113 } 114 else if ([func isEqualToString:@"menuOnePassword"] || [func isEqualToString:@"menuRefresh"] || [func isEqualToString:@"menuShare"]) { 115 cell.userInteractionEnabled = haveURL; 116 cell.textLabel.enabled = haveURL; 117 } 118 else if ([func isEqualToString:@"menuURLBlocker"] && haveURL) { 119 long ruleCount = [[[[appDelegate webViewController] curWebViewTab] applicableURLBlockerTargets] count]; 120 121 if (ruleCount > 0) { 122 cell.detailTextLabel.text = [NSString stringWithFormat:@"%ld host%@ blocked", ruleCount, (ruleCount == 1 ? @"" : @"s")]; 123 cell.detailTextLabel.textColor = [self colorForMenuTextHighlight]; 124 } 125 } 126 else if ([func isEqualToString:@"menuHTTPSEverywhere"] && haveURL) { 127 long ruleCount = [[[[appDelegate webViewController] curWebViewTab] applicableHTTPSEverywhereRules] count]; 128 129 if (ruleCount > 0) { 130 cell.detailTextLabel.text = [NSString stringWithFormat:@"%ld rule%@ in use", ruleCount, (ruleCount == 1 ? @"" : @"s")]; 131 cell.detailTextLabel.textColor = [self colorForMenuTextHighlight]; 132 } 133 } 134 else if ([func isEqualToString:@"menuHostSettings"]) { 135 HostSettings *hs = [HostSettings settingsOrDefaultsForHost:[[[[appDelegate webViewController] curWebViewTab] url] host]]; 136 if (hs && ![hs isDefault]) { 137 cell.detailTextLabel.text = NSLocalizedString(@"Custom settings", nil); 138 cell.detailTextLabel.textColor = [self colorForMenuTextHighlight]; 139 } 140 else { 141 cell.detailTextLabel.text = NSLocalizedString(@"Using defaults", nil); 142 cell.detailTextLabel.textColor = [UIColor grayColor]; 143 } 144 } 145 146 return cell; 147} 148 149- (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath 150{ 151 return 35; 152} 153 154- (BOOL)tableView:(UITableView *)tableView canEditRowAtIndexPath:(NSIndexPath *)indexPath 155{ 156 return NO; 157} 158 159- (BOOL)tableView:(UITableView *)tableView canMoveRowAtIndexPath:(NSIndexPath *)indexPath 160{ 161 return NO; 162} 163 164- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath 165{ 166 [[appDelegate webViewController] dismissPopover]; 167 NSDictionary *button = [buttons objectAtIndex:[indexPath row]]; 168 169 SEL action = NSSelectorFromString([button objectForKey:FUNC]); 170 171 if ([self respondsToSelector:action]) 172 [self performSelector:action]; 173 else 174 NSLog(@"can't call %@", NSStringFromSelector(action)); 175} 176 177 178/* individual menu item functions */ 179 180 181- (void)menuRefresh 182{ 183 [[appDelegate webViewController] forceRefresh]; 184} 185 186- (void)menuOnePassword 187{ 188 [[OnePasswordExtension sharedExtension] fillItemIntoWebView:[[[appDelegate webViewController] curWebViewTab] webView] forViewController:[appDelegate webViewController] sender:[[appDelegate webViewController] settingsButton] showOnlyLogins:NO completion:^(BOOL success, NSError *error) { 189 if (!success) 190 NSLog(@"[OnePasswordExtension] failed to fill into webview: %@", error); 191 }]; 192} 193 194- (void)menuURLBlocker 195{ 196 URLBlockerRuleController *ubrc = [[URLBlockerRuleController alloc] init]; 197 UINavigationController *navController = [[UINavigationController alloc] initWithRootViewController:ubrc]; 198 [[appDelegate webViewController] presentViewController:navController animated:YES completion:nil]; 199} 200 201- (void)menuHTTPSEverywhere 202{ 203 HTTPSEverywhereRuleController *herc = [[HTTPSEverywhereRuleController alloc] init]; 204 UINavigationController *navController = [[UINavigationController alloc] initWithRootViewController:herc]; 205 [[appDelegate webViewController] presentViewController:navController animated:YES completion:nil]; 206} 207 208- (void)menuHostSettings 209{ 210 HostSettingsController *hsc = [[HostSettingsController alloc] init]; 211 UINavigationController *navController = [[UINavigationController alloc] initWithRootViewController:hsc]; 212 [[appDelegate webViewController] presentViewController:navController animated:YES completion:nil]; 213 214 /* if we have custom settings, skip directly to them */ 215 HostSettings *hs = [HostSettings settingsOrDefaultsForHost:[[[[appDelegate webViewController] curWebViewTab] url] host]]; 216 if (hs && ![hs isDefault]) 217 [hsc showDetailsForHost:[hs hostname]]; 218} 219 220- (void)menuAddOrManageBookmarks 221{ 222 [[appDelegate webViewController] showBookmarksForEditing:YES]; 223} 224 225- (void)menuSettings 226{ 227 if (!appSettingsViewController) { 228 appSettingsViewController = [[IASKAppSettingsViewController alloc] init]; 229 appSettingsViewController.delegate = [appDelegate webViewController]; 230 appSettingsViewController.showDoneButton = YES; 231 appSettingsViewController.showCreditsFooter = NO; 232 } 233 234 UINavigationController *navController = [[UINavigationController alloc] initWithRootViewController:appSettingsViewController]; 235 [[appDelegate webViewController] presentViewController:navController animated:YES completion:nil]; 236} 237 238- (void)menuShare 239{ 240 TUSafariActivity *activity = [[TUSafariActivity alloc] init]; 241 UIActivityViewController *avc = [[UIActivityViewController alloc] initWithActivityItems:@[ [[appDelegate webViewController] curWebViewTab] ] applicationActivities:@[ activity ]]; 242 243 UIPopoverPresentationController *popover = [avc popoverPresentationController]; 244 if (popover) { 245 popover.sourceView = [[appDelegate webViewController] settingsButton]; 246 popover.sourceRect = CGRectMake(1, popover.sourceView.frame.size.height / 2, 1, 1); 247 popover.permittedArrowDirections = UIPopoverArrowDirectionAny; 248 } 249 250 [[appDelegate webViewController] presentViewController:avc animated:YES completion:nil]; 251} 252 253- (UIColor *)colorForMenuTextHighlight 254{ 255 if ([[appDelegate webViewController] darkInterface]) 256 return [UIColor colorWithRed:1 green:1 blue:0.69f alpha:1]; 257 else 258 return [UIColor colorWithRed:0 green:0.5 blue:0 alpha:1]; 259} 260 261@end