iOS web browser with a focus on security and privacy
at remove_ckhttpconnection 231 lines 6.1 kB view raw
1/* 2 * Endless 3 * Copyright (c) 2015 joshua stein <jcs@jcs.org> 4 * 5 * See LICENSE file for redistribution terms. 6 */ 7 8#import "AppDelegate.h" 9#import "HostSettings.h" 10 11@implementation HostSettings 12 13static NSMutableDictionary *_hosts; 14 15+ (NSDictionary *)defaults 16{ 17 return @{ 18 HOST_SETTINGS_KEY_TLS: HOST_SETTINGS_TLS_AUTO, 19 HOST_SETTINGS_KEY_CSP: HOST_SETTINGS_CSP_OPEN, 20 HOST_SETTINGS_KEY_BLOCK_LOCAL_NETS: HOST_SETTINGS_VALUE_YES, 21 HOST_SETTINGS_KEY_ALLOW_MIXED_MODE: HOST_SETTINGS_VALUE_NO, 22 HOST_SETTINGS_KEY_WHITELIST_COOKIES: HOST_SETTINGS_VALUE_NO, 23 }; 24} 25 26+ (NSString *)hostSettingsPath 27{ 28 NSString *path = [NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES) lastObject]; 29 return [path stringByAppendingPathComponent:@"host_settings.plist"]; 30} 31 32+ (NSMutableDictionary *)hosts 33{ 34 if (!_hosts) { 35 NSFileManager *fileManager = [NSFileManager defaultManager]; 36 if ([fileManager fileExistsAtPath:[self hostSettingsPath]]) { 37 NSDictionary *td = [NSMutableDictionary dictionaryWithContentsOfFile:[self hostSettingsPath]]; 38 39 _hosts = [[NSMutableDictionary alloc] initWithCapacity:[td count]]; 40 41 for (NSString *k in [td allKeys]) 42 [_hosts setObject:[[HostSettings alloc] initForHost:k withDict:[td objectForKey:k]] forKey:k]; 43 } 44 else 45 _hosts = [[NSMutableDictionary alloc] initWithCapacity:20]; 46 47 /* ensure default host exists */ 48 if (![_hosts objectForKey:HOST_SETTINGS_DEFAULT]) { 49 HostSettings *hs = [[HostSettings alloc] initForHost:HOST_SETTINGS_DEFAULT withDict:nil]; 50 [hs save]; 51 [HostSettings persist]; 52 } 53 } 54 55 return _hosts; 56} 57 58+ (void)persist 59{ 60 if ([(AppDelegate *)[[UIApplication sharedApplication] delegate] areTesting]) 61 abort(); 62 63 NSMutableDictionary *td = [[NSMutableDictionary alloc] initWithCapacity:[[self hosts] count]]; 64 for (NSString *k in [[self hosts] allKeys]) 65 [td setObject:[[[self hosts] objectForKey:k] dict] forKey:k]; 66 67 [td writeToFile:[self hostSettingsPath] atomically:YES]; 68} 69 70+ (HostSettings *)forHost:(NSString *)host 71{ 72 return [[self hosts] objectForKey:host]; 73} 74 75+ (HostSettings *)settingsOrDefaultsForHost:(NSString *)host 76{ 77 HostSettings *hs = [self forHost:host]; 78 if (!hs) { 79 /* for a host of x.y.z.example.com, try y.z.example.com, z.example.com, example.com, etc. */ 80 NSArray *hostp = [host componentsSeparatedByString:@"."]; 81 for (int i = 1; i < [hostp count]; i++) { 82 NSString *wc = [[hostp subarrayWithRange:NSMakeRange(i, [hostp count] - i)] componentsJoinedByString:@"."]; 83 84 if ((hs = [HostSettings forHost:wc])) { 85#ifdef TRACE_HOST_SETTINGS 86 NSLog(@"[HostSettings] found entry for component %@ in %@", wc, host); 87#endif 88 break; 89 } 90 } 91 } 92 93 if (!hs) 94 hs = [self defaultHostSettings]; 95 96 return hs; 97} 98 99+ (BOOL)removeSettingsForHost:(NSString *)host 100{ 101 HostSettings *h = [self forHost:host]; 102 if (h && ![h isDefault]) { 103 [[self hosts] removeObjectForKey:host]; 104 return YES; 105 } 106 107 return NO; 108} 109 110+ (HostSettings *)defaultHostSettings 111{ 112 return [self forHost:HOST_SETTINGS_DEFAULT]; 113} 114 115#if DEBUG 116/* just for testing */ 117+ (void)overrideHosts:(NSMutableDictionary *)hosts 118{ 119 _hosts = hosts; 120} 121#endif 122 123+ (NSArray *)sortedHosts 124{ 125 NSMutableArray *sorted = [[NSMutableArray alloc] initWithArray:[[self hosts] allKeys]]; 126 [sorted removeObject:HOST_SETTINGS_DEFAULT]; 127 [sorted sortUsingSelector:@selector(localizedCaseInsensitiveCompare:)]; 128 [sorted insertObject:HOST_SETTINGS_DEFAULT atIndex:0]; 129 130 return [[NSArray alloc] initWithArray:sorted]; 131} 132 133- (HostSettings *)initForHost:(NSString *)host withDict:(NSDictionary *)dict 134{ 135 self = [super init]; 136 137 host = [host lowercaseString]; 138 139 if (dict) 140 _dict = [[NSMutableDictionary alloc] initWithDictionary:dict]; 141 else 142 _dict = [[NSMutableDictionary alloc] initWithCapacity:10]; 143 144 [_dict setObject:host forKey:HOST_SETTINGS_KEY_HOST]; 145 146 return self; 147} 148 149- (void)save 150{ 151 [[HostSettings hosts] setObject:self forKey:[[self dict] objectForKey:HOST_SETTINGS_KEY_HOST]]; 152} 153 154- (BOOL)isDefault 155{ 156 return ([[[self dict] objectForKey:HOST_SETTINGS_KEY_HOST] isEqualToString:HOST_SETTINGS_DEFAULT]); 157} 158 159- (NSString *)setting:(NSString *)setting 160{ 161 NSString *val = [[self dict] objectForKey:setting]; 162 if (val != NULL && ![val isKindOfClass:[NSString class]]) { 163 NSLog(@"[HostSettings] setting %@ for %@ was %@, not NSString", setting, [self hostname], [val class]); 164 val = nil; 165 } 166 167 if (val != nil && ![val isEqualToString:@""] && ![val isEqualToString:HOST_SETTINGS_DEFAULT]) 168 return val; 169 170 if (val == nil && [self isDefault]) 171 /* default host entries must have a value for every setting */ 172 return [[HostSettings defaults] objectForKey:setting]; 173 174 return nil; 175} 176 177- (NSString *)settingOrDefault:(NSString *)setting 178{ 179 NSString *val = [self setting:setting]; 180 if (val == nil) 181 /* try default host settings */ 182 val = [[HostSettings defaultHostSettings] setting:setting]; 183 184 return val; 185} 186 187- (BOOL)boolSettingOrDefault:(NSString *)setting 188{ 189 NSString *val = [self settingOrDefault:setting]; 190 if (val != nil && [val isEqualToString:HOST_SETTINGS_VALUE_YES]) 191 return YES; 192 else 193 return NO; 194} 195 196- (void)setSetting:(NSString *)setting toValue:(NSString *)value 197{ 198 if (value == nil || [value isEqualToString:HOST_SETTINGS_DEFAULT]) { 199 [[self dict] removeObjectForKey:setting]; 200 return; 201 } 202 203 if ([setting isEqualToString:HOST_SETTINGS_KEY_TLS]) { 204 if (!([value isEqualToString:HOST_SETTINGS_TLS_12] || [value isEqualToString:HOST_SETTINGS_TLS_AUTO])) 205 return; 206 } 207 208 [[self dict] setObject:value forKey:setting]; 209} 210 211- (NSString *)hostname 212{ 213 if ([self isDefault]) 214 return HOST_SETTINGS_HOST_DEFAULT_LABEL; 215 else 216 return [[self dict] objectForKey:HOST_SETTINGS_KEY_HOST]; 217} 218 219- (void)setHostname:(NSString *)hostname 220{ 221 if ([self isDefault] || !hostname || [hostname isEqualToString:@""]) 222 return; 223 224 hostname = [hostname lowercaseString]; 225 226 [[HostSettings hosts] removeObjectForKey:[[self dict] objectForKey:HOST_SETTINGS_KEY_HOST]]; 227 [[self dict] setObject:hostname forKey:HOST_SETTINGS_KEY_HOST]; 228 [[HostSettings hosts] setObject:self forKey:hostname]; 229} 230 231@end