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 "URLBlocker.h"
9
10@implementation URLBlocker
11
12static NSDictionary *_targets;
13static NSCache *ruleCache;
14
15#define RULE_CACHE_SIZE 20
16
17+ (NSDictionary *)targets
18{
19 if (_targets == nil) {
20 NSString *path = [[NSBundle mainBundle] pathForResource:@"urlblocker_targets" ofType:@"plist"];
21 if (![[NSFileManager defaultManager] fileExistsAtPath:path]) {
22 NSLog(@"[URLBlocker] no target plist at %@", path);
23 abort();
24 }
25
26 _targets = [NSDictionary dictionaryWithContentsOfFile:path];
27
28#ifdef TRACE_URL_BLOCKER
29 NSLog(@"[URLBlocker] locked and loaded with %lu target domains", [_targets count]);
30#endif
31 }
32
33 return _targets;
34}
35
36+ (void)cacheBlockedURL:(NSURL *)url withRule:(NSString *)rule
37{
38 if (!ruleCache) {
39 ruleCache = [[NSCache alloc] init];
40 [ruleCache setCountLimit:RULE_CACHE_SIZE];
41 }
42
43 [ruleCache setObject:rule forKey:url];
44}
45
46+ (NSString *)blockRuleForURL:(NSURL *)url
47{
48 NSString *blocker;
49
50 if (!(ruleCache && (blocker = [ruleCache objectForKey:url]))) {
51 NSString *host = [[url host] lowercaseString];
52
53 blocker = [[[self class] targets] objectForKey:host];
54
55 if (!blocker) {
56 /* now for x.y.z.example.com, try *.y.z.example.com, *.z.example.com, *.example.com, etc. */
57 /* TODO: should we skip the last component for obviously non-matching things like "*.com", "*.net"? */
58 NSArray *hostp = [host componentsSeparatedByString:@"."];
59 for (int i = 1; i < [hostp count]; i++) {
60 NSString *wc = [[hostp subarrayWithRange:NSMakeRange(i, [hostp count] - i)] componentsJoinedByString:@"."];
61
62 if ((blocker = [[[self class] targets] objectForKey:wc]) != nil) {
63 break;
64 }
65 }
66 }
67 }
68
69 if (blocker) {
70 [[self class] cacheBlockedURL:url withRule:blocker];
71 }
72
73 return blocker;
74}
75
76+ (BOOL)shouldBlockURL:(NSURL *)url
77{
78 return ([self blockRuleForURL:url] != nil);
79}
80
81+ (BOOL)shouldBlockURL:(NSURL *)url fromMainDocumentURL:(NSURL *)mainUrl
82{
83 NSString *blocker = [self blockRuleForURL:url];
84 if (blocker != nil && mainUrl != nil) {
85 /* if this same rule would have blocked our main URL, allow it since the user is probably viewing this site and this isn't a sneaky tracker */
86 if ([blocker isEqualToString:[self blockRuleForURL:mainUrl]]) {
87 return NO;
88 }
89
90#ifdef TRACE_URL_BLOCKER
91 NSLog(@"[URLBlocker] blocking %@ (via %@) (%@)", url, mainUrl, blocker);
92#endif
93
94 return YES;
95 }
96
97 return NO;
98}
99
100@end