Skip to content
This repository has been archived by the owner on Nov 6, 2021. It is now read-only.

Commit

Permalink
add an HTTP Strict Transport Security (RFC6797) implementation
Browse files Browse the repository at this point in the history
It wasn't until I was about 90% finished with all of this that I
realized that WebKit already has its own HSTS implementation behind
the scenes that caches entries and has a preload list of a few
hundred domains.  Oh well.

Since we can't manipulate that list, continue with our own and
preload it with Chromium's preload list (which Mozilla also appears
to use), which currently has 1427 hosts and is freely licensed.
  • Loading branch information
jcs committed Sep 12, 2015
1 parent 6b1d988 commit d200ceb
Show file tree
Hide file tree
Showing 16 changed files with 7,655 additions and 49 deletions.
104 changes: 104 additions & 0 deletions Endless Tests/HSTSCache_Tests.m
Original file line number Diff line number Diff line change
@@ -0,0 +1,104 @@
#import <UIKit/UIKit.h>
#import <XCTest/XCTest.h>
#import <OCMock/OCMock.h>

#import "HSTSCache.h"

#define TRACE_HSTS

@interface HSTSCache_Tests : XCTestCase
@end

@implementation HSTSCache_Tests

HSTSCache *hstsCache;

- (void)setUp {
[super setUp];

hstsCache = [[HSTSCache alloc] init];
}

- (void)testParseHSTSHeader {
[hstsCache parseHSTSHeader:@"max-age=12345; includeSubDomains" forHost:@"example.com"];

NSDictionary *params = [hstsCache objectForKey:@"example.com"];
XCTAssertNotNil(params);
XCTAssertNotNil([params objectForKey:HSTS_KEY_ALLOW_SUBDOMAINS]);
XCTAssertNotNil([params objectForKey:HSTS_KEY_EXPIRATION]);

XCTAssertTrue([(NSDate *)[params objectForKey:HSTS_KEY_EXPIRATION] timeIntervalSince1970] - [[NSDate date] timeIntervalSince1970] >= 12340);
}

- (void)testIgnoreIPAddresses {
[hstsCache parseHSTSHeader:@"max-age=12345; includeSubDomains" forHost:@"127.0.0.1"];

NSDictionary *params = [hstsCache objectForKey:@"127.0.0.1"];
XCTAssertNil(params);
}

- (void)testParseUpdatedHSTSHeader {
[hstsCache parseHSTSHeader:@"max-age=12345; includeSubDomains" forHost:@"example.com"];

NSDictionary *params = [hstsCache objectForKey:@"example.com"];
XCTAssertNotNil(params);
XCTAssertNotNil([params objectForKey:HSTS_KEY_ALLOW_SUBDOMAINS]);

/* now a new request presents without includeSubDomains */
[hstsCache parseHSTSHeader:@"max-age=12345" forHost:@"example.com"];

params = [hstsCache objectForKey:@"example.com"];
XCTAssertNotNil(params);
XCTAssertNil([params objectForKey:HSTS_KEY_ALLOW_SUBDOMAINS]);
}

- (void)testParseEFFHSTSHeader {
/* weirdo header that eff sends (to cover old spec?) */
[hstsCache parseHSTSHeader:@"max-age=31536000; includeSubdomains, max-age=31536000; includeSubdomains" forHost:@"www.EFF.org"];

NSDictionary *params = [hstsCache objectForKey:@"www.eff.org"];
XCTAssertNotNil(params);
XCTAssertNotNil([params objectForKey:HSTS_KEY_ALLOW_SUBDOMAINS]);
XCTAssertNotNil([params objectForKey:HSTS_KEY_EXPIRATION]);
}

- (void)testURLRewriting {
[hstsCache parseHSTSHeader:@"max-age=31536000; includeSubdomains, max-age=31536000; includeSubdomains" forHost:@"www.EFF.org"];

NSURL *output = [hstsCache rewrittenURI:[NSURL URLWithString:@"http://www.eff.org/test"]];
XCTAssertTrue([[output absoluteString] isEqualToString:@"https://www.eff.org/test"]);

/* we didn't see the header for "eff.org", so subdomains have to be of www */
output = [hstsCache rewrittenURI:[NSURL URLWithString:@"http://subdomain.eff.org/test"]];
XCTAssertFalse([[output absoluteString] isEqualToString:@"https://subdomain.eff.org/test"]);

output = [hstsCache rewrittenURI:[NSURL URLWithString:@"http://subdomain.www.eff.org/test"]];
XCTAssertTrue([[output absoluteString] isEqualToString:@"https://subdomain.www.eff.org/test"]);

output = [hstsCache rewrittenURI:[NSURL URLWithString:@"http://www.eff.org:1234/?what#hi"]];
XCTAssertTrue([[output absoluteString] isEqualToString:@"https://www.eff.org:1234/?what#hi"]);

output = [hstsCache rewrittenURI:[NSURL URLWithString:@"http://www.eff.org:80/?what#hi"]];
XCTAssertTrue([[output absoluteString] isEqualToString:@"https://www.eff.org/?what#hi"]);
}

- (void)testExpiring {
[hstsCache parseHSTSHeader:@"max-age=2; includeSubDomains" forHost:@"example.com"];

NSURL *output = [hstsCache rewrittenURI:[NSURL URLWithString:@"http://www.example.com/"]];
XCTAssertTrue([[output absoluteString] isEqualToString:@"https://www.example.com/"]);

NSDate *timeoutDate = [NSDate dateWithTimeIntervalSinceNow:4];

do {
[[NSRunLoop currentRunLoop] runMode:NSDefaultRunLoopMode beforeDate:timeoutDate];
if ([timeoutDate timeIntervalSinceNow] < 0)
break;
} while (TRUE);

/* expired */
output = [hstsCache rewrittenURI:[NSURL URLWithString:@"http://www.example.com/"]];
XCTAssertTrue([[output absoluteString] isEqualToString:@"http://www.example.com/"]);
}

@end
46 changes: 33 additions & 13 deletions Endless.xcodeproj/project.pbxproj
Original file line number Diff line number Diff line change
Expand Up @@ -8,9 +8,10 @@

/* Begin PBXBuildFile section */
010EEA661A43A536001E8B65 /* CookieController.m in Sources */ = {isa = PBXBuildFile; fileRef = 010EEA651A43A536001E8B65 /* CookieController.m */; };
010EEA691A43C8CF001E8B65 /* CookieWhitelist.m in Sources */ = {isa = PBXBuildFile; fileRef = 010EEA681A43C8CF001E8B65 /* CookieWhitelist.m */; };
010EEA691A43C8CF001E8B65 /* CookieJar.m in Sources */ = {isa = PBXBuildFile; fileRef = 010EEA681A43C8CF001E8B65 /* CookieJar.m */; };
0135F4761A3D2931005A8F16 /* SearchEngines.plist in Resources */ = {isa = PBXBuildFile; fileRef = 0135F4751A3D2931005A8F16 /* SearchEngines.plist */; };
0135F47F1A3E548F005A8F16 /* WebViewTab.m in Sources */ = {isa = PBXBuildFile; fileRef = 0135F47E1A3E548F005A8F16 /* WebViewTab.m */; };
016B2FCB1A53466D002D2730 /* hsts_preload.plist in Resources */ = {isa = PBXBuildFile; fileRef = 016B2FCA1A53466D002D2730 /* hsts_preload.plist */; };
01801E981A32CA2A002B4718 /* main.m in Sources */ = {isa = PBXBuildFile; fileRef = 01801E971A32CA2A002B4718 /* main.m */; };
01801E9B1A32CA2A002B4718 /* AppDelegate.m in Sources */ = {isa = PBXBuildFile; fileRef = 01801E9A1A32CA2A002B4718 /* AppDelegate.m */; };
01801EA11A32CA2A002B4718 /* WebViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = 01801EA01A32CA2A002B4718 /* WebViewController.m */; };
Expand All @@ -23,10 +24,13 @@
018333E91A35746500670CD1 /* https-everywhere_rules.plist in Resources */ = {isa = PBXBuildFile; fileRef = 018333E71A35746500670CD1 /* https-everywhere_rules.plist */; };
018333EA1A35746500670CD1 /* https-everywhere_targets.plist in Resources */ = {isa = PBXBuildFile; fileRef = 018333E81A35746500670CD1 /* https-everywhere_targets.plist */; };
01D741281A44DF1C007B7033 /* WebViewMenuController.m in Sources */ = {isa = PBXBuildFile; fileRef = 01D741271A44DF1C007B7033 /* WebViewMenuController.m */; };
01D7412A1A45EDD1007B7033 /* CookieWhitelist_Tests.m in Sources */ = {isa = PBXBuildFile; fileRef = 01D741291A45EDD1007B7033 /* CookieWhitelist_Tests.m */; };
01D7412A1A45EDD1007B7033 /* CookieJar_Tests.m in Sources */ = {isa = PBXBuildFile; fileRef = 01D741291A45EDD1007B7033 /* CookieJar_Tests.m */; };
01D7412C1A45F8EB007B7033 /* injected.js in Resources */ = {isa = PBXBuildFile; fileRef = 01D7412B1A45F8EB007B7033 /* injected.js */; };
01D7412F1A466AF0007B7033 /* NSString+JavascriptEscape.m in Sources */ = {isa = PBXBuildFile; fileRef = 01D7412E1A466AF0007B7033 /* NSString+JavascriptEscape.m */; };
01D741321A49EA14007B7033 /* HTTPSEverywhereRuleController.m in Sources */ = {isa = PBXBuildFile; fileRef = 01D741311A49EA14007B7033 /* HTTPSEverywhereRuleController.m */; };
01F7CB491A5253DD00F42B73 /* HSTSCache.m in Sources */ = {isa = PBXBuildFile; fileRef = 01F7CB481A5253DD00F42B73 /* HSTSCache.m */; };
01F7CB4B1A526B9C00F42B73 /* HSTSCache_Tests.m in Sources */ = {isa = PBXBuildFile; fileRef = 01F7CB4A1A526B9C00F42B73 /* HSTSCache_Tests.m */; };
01F7CB4E1A52FC4E00F42B73 /* NSString+IPAddress.m in Sources */ = {isa = PBXBuildFile; fileRef = 01F7CB4D1A52FC4E00F42B73 /* NSString+IPAddress.m */; };
01F8793B1A4108DD00A63654 /* URLBlocker.m in Sources */ = {isa = PBXBuildFile; fileRef = 01F8793A1A4108DD00A63654 /* URLBlocker.m */; };
01F879411A4112E500A63654 /* URLBlocker_Tests.m in Sources */ = {isa = PBXBuildFile; fileRef = 01F879401A4112E500A63654 /* URLBlocker_Tests.m */; };
01F879441A41140D00A63654 /* https-everywhere_mock_rules.plist in Resources */ = {isa = PBXBuildFile; fileRef = 01F879421A41140D00A63654 /* https-everywhere_mock_rules.plist */; };
Expand Down Expand Up @@ -55,11 +59,12 @@
/* Begin PBXFileReference section */
010EEA641A43A536001E8B65 /* CookieController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = CookieController.h; sourceTree = "<group>"; };
010EEA651A43A536001E8B65 /* CookieController.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = CookieController.m; sourceTree = "<group>"; };
010EEA671A43C8CF001E8B65 /* CookieWhitelist.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = CookieWhitelist.h; sourceTree = "<group>"; };
010EEA681A43C8CF001E8B65 /* CookieWhitelist.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = CookieWhitelist.m; sourceTree = "<group>"; };
010EEA671A43C8CF001E8B65 /* CookieJar.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = CookieJar.h; sourceTree = "<group>"; };
010EEA681A43C8CF001E8B65 /* CookieJar.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = CookieJar.m; sourceTree = "<group>"; };
0135F4751A3D2931005A8F16 /* SearchEngines.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; name = SearchEngines.plist; path = Endless/Resources/SearchEngines.plist; sourceTree = "<group>"; };
0135F47D1A3E548F005A8F16 /* WebViewTab.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = WebViewTab.h; sourceTree = "<group>"; };
0135F47E1A3E548F005A8F16 /* WebViewTab.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = WebViewTab.m; sourceTree = "<group>"; };
016B2FCA1A53466D002D2730 /* hsts_preload.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist; name = hsts_preload.plist; path = Endless/Resources/hsts_preload.plist; sourceTree = "<group>"; };
01801E921A32CA2A002B4718 /* Endless.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = Endless.app; sourceTree = BUILT_PRODUCTS_DIR; };
01801E961A32CA2A002B4718 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = "<group>"; };
01801E971A32CA2A002B4718 /* main.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = main.m; sourceTree = "<group>"; };
Expand All @@ -84,12 +89,17 @@
018333EB1A357D8B00670CD1 /* libPods-OCMock.a */ = {isa = PBXFileReference; lastKnownFileType = archive.ar; name = "libPods-OCMock.a"; path = "Pods/build/Debug-iphoneos/libPods-OCMock.a"; sourceTree = "<group>"; };
01D741261A44DF1C007B7033 /* WebViewMenuController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = WebViewMenuController.h; sourceTree = "<group>"; };
01D741271A44DF1C007B7033 /* WebViewMenuController.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = WebViewMenuController.m; sourceTree = "<group>"; };
01D741291A45EDD1007B7033 /* CookieWhitelist_Tests.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = CookieWhitelist_Tests.m; sourceTree = "<group>"; };
01D741291A45EDD1007B7033 /* CookieJar_Tests.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = CookieJar_Tests.m; sourceTree = "<group>"; };
01D7412B1A45F8EB007B7033 /* injected.js */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.javascript; name = injected.js; path = Endless/Resources/injected.js; sourceTree = "<group>"; };
01D7412D1A466AF0007B7033 /* NSString+JavascriptEscape.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "NSString+JavascriptEscape.h"; sourceTree = "<group>"; };
01D7412E1A466AF0007B7033 /* NSString+JavascriptEscape.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = "NSString+JavascriptEscape.m"; sourceTree = "<group>"; };
01D741301A49EA14007B7033 /* HTTPSEverywhereRuleController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = HTTPSEverywhereRuleController.h; sourceTree = "<group>"; };
01D741311A49EA14007B7033 /* HTTPSEverywhereRuleController.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = HTTPSEverywhereRuleController.m; sourceTree = "<group>"; };
01F7CB471A5253DD00F42B73 /* HSTSCache.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = HSTSCache.h; sourceTree = "<group>"; };
01F7CB481A5253DD00F42B73 /* HSTSCache.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = HSTSCache.m; sourceTree = "<group>"; };
01F7CB4A1A526B9C00F42B73 /* HSTSCache_Tests.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = HSTSCache_Tests.m; sourceTree = "<group>"; };
01F7CB4C1A52FC4E00F42B73 /* NSString+IPAddress.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "NSString+IPAddress.h"; sourceTree = "<group>"; };
01F7CB4D1A52FC4E00F42B73 /* NSString+IPAddress.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = "NSString+IPAddress.m"; sourceTree = "<group>"; };
01F879391A4108DD00A63654 /* URLBlocker.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = URLBlocker.h; sourceTree = "<group>"; };
01F8793A1A4108DD00A63654 /* URLBlocker.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = URLBlocker.m; sourceTree = "<group>"; };
01F879401A4112E500A63654 /* URLBlocker_Tests.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = URLBlocker_Tests.m; sourceTree = "<group>"; };
Expand Down Expand Up @@ -156,10 +166,12 @@
children = (
01801E991A32CA2A002B4718 /* AppDelegate.h */,
01801E9A1A32CA2A002B4718 /* AppDelegate.m */,
010EEA671A43C8CF001E8B65 /* CookieWhitelist.h */,
010EEA681A43C8CF001E8B65 /* CookieWhitelist.m */,
010EEA671A43C8CF001E8B65 /* CookieJar.h */,
010EEA681A43C8CF001E8B65 /* CookieJar.m */,
010EEA641A43A536001E8B65 /* CookieController.h */,
010EEA651A43A536001E8B65 /* CookieController.m */,
01F7CB471A5253DD00F42B73 /* HSTSCache.h */,
01F7CB481A5253DD00F42B73 /* HSTSCache.m */,
01D741301A49EA14007B7033 /* HTTPSEverywhereRuleController.h */,
01D741311A49EA14007B7033 /* HTTPSEverywhereRuleController.m */,
018333C81A3505FB00670CD1 /* HTTPSEverywhere.h */,
Expand All @@ -183,11 +195,13 @@
01801E951A32CA2A002B4718 /* Supporting Files */ = {
isa = PBXGroup;
children = (
01D7412D1A466AF0007B7033 /* NSString+JavascriptEscape.h */,
01D7412E1A466AF0007B7033 /* NSString+JavascriptEscape.m */,
018333CF1A351B3B00670CD1 /* Endless-Prefix.pch */,
01801E961A32CA2A002B4718 /* Info.plist */,
01801E971A32CA2A002B4718 /* main.m */,
018333CF1A351B3B00670CD1 /* Endless-Prefix.pch */,
01F7CB4C1A52FC4E00F42B73 /* NSString+IPAddress.h */,
01F7CB4D1A52FC4E00F42B73 /* NSString+IPAddress.m */,
01D7412D1A466AF0007B7033 /* NSString+JavascriptEscape.h */,
01D7412E1A466AF0007B7033 /* NSString+JavascriptEscape.m */,
);
name = "Supporting Files";
path = Endless;
Expand All @@ -199,6 +213,7 @@
01801EC21A3360F8002B4718 /* InAppSettings.bundle */,
01F8794A1A41232E00A63654 /* credits.html */,
01D7412B1A45F8EB007B7033 /* injected.js */,
016B2FCA1A53466D002D2730 /* hsts_preload.plist */,
018333E71A35746500670CD1 /* https-everywhere_rules.plist */,
018333E81A35746500670CD1 /* https-everywhere_targets.plist */,
0135F4751A3D2931005A8F16 /* SearchEngines.plist */,
Expand All @@ -211,9 +226,10 @@
018333D81A35727C00670CD1 /* Endless Tests */ = {
isa = PBXGroup;
children = (
01D741291A45EDD1007B7033 /* CookieJar_Tests.m */,
01F7CB4A1A526B9C00F42B73 /* HSTSCache_Tests.m */,
018333DB1A35727C00670CD1 /* HTTPSEverywhere_Tests.m */,
01F879401A4112E500A63654 /* URLBlocker_Tests.m */,
01D741291A45EDD1007B7033 /* CookieWhitelist_Tests.m */,
018333D91A35727C00670CD1 /* Supporting Files */,
);
path = "Endless Tests";
Expand Down Expand Up @@ -345,6 +361,7 @@
01F8794F1A412FA500A63654 /* urlblocker_targets.plist in Resources */,
01801EA61A32CA2A002B4718 /* Images.xcassets in Resources */,
01F8794C1A4124FE00A63654 /* credits.html in Resources */,
016B2FCB1A53466D002D2730 /* hsts_preload.plist in Resources */,
);
runOnlyForDeploymentPostprocessing = 0;
};
Expand Down Expand Up @@ -441,18 +458,21 @@
01F8793B1A4108DD00A63654 /* URLBlocker.m in Sources */,
01801EC01A335BEC002B4718 /* URLInterceptor.m in Sources */,
018333CA1A3505FB00670CD1 /* HTTPSEverywhere.m in Sources */,
01F7CB491A5253DD00F42B73 /* HSTSCache.m in Sources */,
01F7CB4E1A52FC4E00F42B73 /* NSString+IPAddress.m in Sources */,
0135F47F1A3E548F005A8F16 /* WebViewTab.m in Sources */,
010EEA661A43A536001E8B65 /* CookieController.m in Sources */,
010EEA691A43C8CF001E8B65 /* CookieWhitelist.m in Sources */,
010EEA691A43C8CF001E8B65 /* CookieJar.m in Sources */,
);
runOnlyForDeploymentPostprocessing = 0;
};
018333D31A35727C00670CD1 /* Sources */ = {
isa = PBXSourcesBuildPhase;
buildActionMask = 2147483647;
files = (
01F7CB4B1A526B9C00F42B73 /* HSTSCache_Tests.m in Sources */,
01F879411A4112E500A63654 /* URLBlocker_Tests.m in Sources */,
01D7412A1A45EDD1007B7033 /* CookieWhitelist_Tests.m in Sources */,
01D7412A1A45EDD1007B7033 /* CookieJar_Tests.m in Sources */,
018333DC1A35727C00670CD1 /* HTTPSEverywhere_Tests.m in Sources */,
);
runOnlyForDeploymentPostprocessing = 0;
Expand Down
2 changes: 2 additions & 0 deletions Endless/AppDelegate.h
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
#import <CoreData/CoreData.h>

#import "CookieJar.h"
#import "HSTSCache.h"
#import "WebViewController.h"

@interface AppDelegate : UIResponder <UIApplicationDelegate>
Expand All @@ -14,6 +15,7 @@

@property (strong, atomic) WebViewController *webViewController;
@property (strong, atomic) CookieJar *cookieJar;
@property (strong, atomic) HSTSCache *hstsCache;

@property (readonly, strong, nonatomic) NSMutableDictionary *searchEngines;

Expand Down
3 changes: 3 additions & 0 deletions Endless/Endless-Prefix.pch
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,9 @@
/* be verbose about javascript IPC */
//# define TRACE_IPC

/* be verbose about HTTP Strict Transport Security */
//# define TRACE_HSTS

#endif

#endif
30 changes: 30 additions & 0 deletions Endless/HSTSCache.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
#import <Foundation/Foundation.h>

#define HSTS_HEADER @"Strict-Transport-Security"
#define HSTS_KEY_EXPIRATION @"expiration"
#define HSTS_KEY_ALLOW_SUBDOMAINS @"allowSubdomains"
#define HSTS_KEY_PRELOADED @"preloaded"

/* subclassing NSMutableDictionary is not easy, so we have to use composition */

@interface HSTSCache : NSObject
{
NSMutableDictionary *_dict;
}

@property NSMutableDictionary *dict;

+ (HSTSCache *)retrieve;

- (void)persist;
- (NSURL *)rewrittenURI:(NSURL *)URL;
- (void)parseHSTSHeader:(NSString *)header forHost:(NSString *)host;

/* NSMutableDictionary composition pass-throughs */
- (id)objectForKey:(id)aKey;
- (BOOL)writeToFile:(NSString *)path atomically:(BOOL)useAuxiliaryFile;
- (void)setValue:(id)value forKey:(NSString *)key;
- (void)removeObjectForKey:(id)aKey;
- (NSArray *)allKeys;

@end
Loading

0 comments on commit d200ceb

Please sign in to comment.