iOS web browser with a focus on security and privacy
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