Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with
or
.
Download ZIP
Browse files

Fixed #246 Add whitelist capability that includes XMLHttpRequest calls

  • Loading branch information...
commit afda6a9b2754b4e4e448356c0535651d4df9ca8f 1 parent 5544b2a
@shazron shazron authored
View
23 PhoneGapLib/Classes/PGURLProtocol.h
@@ -0,0 +1,23 @@
+//
+// PGURLProtocol.h
+// PhoneGapLib
+//
+// Created by Shazron Abdullah on 11-08-25.
+// Copyright 2011 Nitobi Sofware Inc. All rights reserved.
+//
+
+#import <Foundation/Foundation.h>
+
+@interface PGURLProtocol : NSURLProtocol {
+}
+
++ (void) registerPGHttpURLProtocol;
+
+@end
+
+@interface PGHTTPURLResponse : NSHTTPURLResponse {
+}
+
+- (PGHTTPURLResponse*) initWithUnauthorizedURL:(NSURL*)url;
+
+@end
View
107 PhoneGapLib/Classes/PGURLProtocol.m
@@ -0,0 +1,107 @@
+//
+// PGURLProtocol.m
+// PhoneGapLib
+//
+// Created by Shazron Abdullah on 11-08-25.
+// Copyright 2011 Nitobi Software Inc. All rights reserved.
+//
+
+#import "PGURLProtocol.h"
+#import "PGWhitelist.h"
+#import "PhoneGapDelegate.h"
+
+static PGWhitelist* gWhitelist = nil;
+
+@implementation PGURLProtocol
+
+// Called before any use of the protocol, ensure it is only called once
++ (void) registerPGHttpURLProtocol {
+ static BOOL registered = NO;
+ if (!registered) {
+ [NSURLProtocol registerClass:[PGURLProtocol class]];
+ registered = YES;
+ }
+}
+
++ (BOOL) canInitWithRequest:(NSURLRequest *)theRequest
+{
+ NSURL* theUrl = [theRequest URL];
+ NSString* theScheme = [theUrl scheme];
+
+ if (gWhitelist == nil) {
+ PhoneGapDelegate* delegate = (PhoneGapDelegate*)[[UIApplication sharedApplication] delegate];
+ gWhitelist = [delegate.whitelist retain];
+ }
+
+ // we only care about http and https connections
+ if ([gWhitelist schemeIsAllowed:theScheme])
+ {
+ // if it FAILS the whitelist, we return TRUE, so we can fail the connection later
+ return ![gWhitelist URLIsAllowed:theUrl];
+ }
+
+ return NO;
+}
+
++ (NSURLRequest*) canonicalRequestForRequest:(NSURLRequest*) request
+{
+ //NSLog(@"%@ received %@", self, NSStringFromSelector(_cmd));
+ return request;
+}
+
+- (void) startLoading
+{
+ //NSLog(@"%@ received %@ - start", self, NSStringFromSelector(_cmd));
+ NSURL* url = [[self request] URL];
+ NSString* body = [gWhitelist errorStringForURL:url];
+
+ PGHTTPURLResponse* response = [[PGHTTPURLResponse alloc] initWithUnauthorizedURL:url];
+
+ [[self client] URLProtocol:self didReceiveResponse:response cacheStoragePolicy:NSURLCacheStorageNotAllowed];
+
+ [[self client] URLProtocol:self didLoadData:[body dataUsingEncoding:NSASCIIStringEncoding]];
+
+ [[self client] URLProtocolDidFinishLoading:self];
+
+ [response release];
+}
+
+- (void) stopLoading
+{
+ // do any cleanup here
+}
+
++ (BOOL) requestIsCacheEquivalent: (NSURLRequest*)requestA toRequest: (NSURLRequest*)requestB
+{
+ return NO;
+}
+
+@end
+
+
+
+@implementation PGHTTPURLResponse
+
+- (id) initWithUnauthorizedURL:(NSURL*)url
+{
+ NSInteger statusCode = 401;
+ NSDictionary* headerFields = [NSDictionary dictionaryWithObject:@"Digest realm = \"PhoneGap.plist/ExternalHosts\"" forKey:@"WWW-Authenticate"];
+ double requestTime = 1;
+
+ SEL selector = NSSelectorFromString(@"initWithURL:statusCode:headerFields:requestTime:");
+ NSMethodSignature* signature = [self methodSignatureForSelector:selector];
+
+ NSInvocation* inv = [NSInvocation invocationWithMethodSignature:signature];
+ [inv setTarget:self];
+ [inv setSelector:selector];
+ [inv setArgument:&url atIndex:2];
+ [inv setArgument:&statusCode atIndex:3];
+ [inv setArgument:&headerFields atIndex:4];
+ [inv setArgument:&requestTime atIndex:5];
+
+ [inv invoke];
+
+ return self;
+}
+
+@end
View
2  PhoneGapLib/Classes/PGWhitelist.h
@@ -14,5 +14,7 @@
- (id) initWithArray:(NSArray*)array;
- (BOOL) URLIsAllowed:(NSURL*)url;
+- (BOOL) schemeIsAllowed:(NSString*)scheme;
+- (NSString*) errorStringForURL:(NSURL*)url;
@end
View
15 PhoneGapLib/Classes/PGWhitelist.m
@@ -22,6 +22,14 @@ - (id) initWithArray:(NSArray*)array
return self;
}
+- (BOOL) schemeIsAllowed:(NSString*)scheme
+{
+ return ([scheme isEqualToString:@"http"] ||
+ [scheme isEqualToString:@"https"] ||
+ [scheme isEqualToString:@"ftp"] ||
+ [scheme isEqualToString:@"ftps"] );
+}
+
- (BOOL) URLIsAllowed:(NSURL*)url
{
if (self.whitelist == nil) {
@@ -69,9 +77,14 @@ - (BOOL) URLIsAllowed:(NSURL*)url
}
}
+ NSLog([self errorStringForURL:url], @"");
// if we got here, the url host is not in the white-list, do nothing
- NSLog(@"ERROR: Url '%@' is not in the white-list at PhoneGap.plist/ExternalHosts", [url description]);
return NO;
}
+- (NSString*) errorStringForURL:(NSURL*)url
+{
+ return [NSString stringWithFormat:@"ERROR whitelist rejection: url='%@'", [url absoluteString]];
+}
+
@end
View
5 PhoneGapLib/Classes/PhoneGapDelegate.m
@@ -14,6 +14,7 @@
#import "DebugConsole.h"
#import "Connection.h"
+#import "PGURLProtocol.h"
#import "PGWhitelist.h"
#import "InvokedUrlCommand.h"
#import "PhoneGapDelegate.h"
@@ -72,6 +73,8 @@ - (id) init
[[UIDevice currentDevice] beginGeneratingDeviceOrientationNotifications];
[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(receivedOrientationChange) name:UIDeviceOrientationDidChangeNotification
object:nil];
+
+ [PGURLProtocol registerPGHttpURLProtocol];
}
return self;
}
@@ -636,7 +639,7 @@ - (BOOL)webView:(UIWebView *)theWebView shouldStartLoadWithRequest:(NSURLRequest
{
return YES;
}
- else if ( [ [url scheme] isEqualToString:@"http"] || [ [url scheme] isEqualToString:@"https"] )
+ else if ([self.whitelist schemeIsAllowed:[url scheme]])
{
if ([self.whitelist URLIsAllowed:url] == YES)
{
View
12 PhoneGapLib/PhoneGapLib.xcodeproj/project.pbxproj
@@ -99,6 +99,10 @@
30C684811406CB38004C1A8E /* PGWhitelist.h in Headers */ = {isa = PBXBuildFile; fileRef = 30C6847E1406CB38004C1A8E /* PGWhitelist.h */; settings = {ATTRIBUTES = (Public, ); }; };
30C684821406CB38004C1A8E /* PGWhitelist.m in Sources */ = {isa = PBXBuildFile; fileRef = 30C6847F1406CB38004C1A8E /* PGWhitelist.m */; };
30C684831406CB38004C1A8E /* PGWhitelist.m in Sources */ = {isa = PBXBuildFile; fileRef = 30C6847F1406CB38004C1A8E /* PGWhitelist.m */; };
+ 30C684941407044B004C1A8E /* PGURLProtocol.h in Headers */ = {isa = PBXBuildFile; fileRef = 30C684921407044A004C1A8E /* PGURLProtocol.h */; };
+ 30C684951407044B004C1A8E /* PGURLProtocol.h in Headers */ = {isa = PBXBuildFile; fileRef = 30C684921407044A004C1A8E /* PGURLProtocol.h */; };
+ 30C684961407044B004C1A8E /* PGURLProtocol.m in Sources */ = {isa = PBXBuildFile; fileRef = 30C684931407044A004C1A8E /* PGURLProtocol.m */; };
+ 30C684971407044B004C1A8E /* PGURLProtocol.m in Sources */ = {isa = PBXBuildFile; fileRef = 30C684931407044A004C1A8E /* PGURLProtocol.m */; };
30E33AF213A7E24B00594D64 /* PGPlugin.h in Headers */ = {isa = PBXBuildFile; fileRef = 30E33AF013A7E24B00594D64 /* PGPlugin.h */; };
30E33AF313A7E24B00594D64 /* PGPlugin.m in Sources */ = {isa = PBXBuildFile; fileRef = 30E33AF113A7E24B00594D64 /* PGPlugin.m */; };
30E563CF13E217EC00C949AA /* NSMutableArray+QueueAdditions.h in Headers */ = {isa = PBXBuildFile; fileRef = 30E563CD13E217EC00C949AA /* NSMutableArray+QueueAdditions.h */; };
@@ -170,6 +174,8 @@
30B39EBD13D0268B0009682A /* PGSplashScreen.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = PGSplashScreen.m; path = Classes/PGSplashScreen.m; sourceTree = "<group>"; };
30C6847E1406CB38004C1A8E /* PGWhitelist.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = PGWhitelist.h; path = Classes/PGWhitelist.h; sourceTree = "<group>"; };
30C6847F1406CB38004C1A8E /* PGWhitelist.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = PGWhitelist.m; path = Classes/PGWhitelist.m; sourceTree = "<group>"; };
+ 30C684921407044A004C1A8E /* PGURLProtocol.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = PGURLProtocol.h; path = Classes/PGURLProtocol.h; sourceTree = "<group>"; };
+ 30C684931407044A004C1A8E /* PGURLProtocol.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = PGURLProtocol.m; path = Classes/PGURLProtocol.m; sourceTree = "<group>"; };
30E33AF013A7E24B00594D64 /* PGPlugin.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = PGPlugin.h; path = Classes/PGPlugin.h; sourceTree = "<group>"; };
30E33AF113A7E24B00594D64 /* PGPlugin.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = PGPlugin.m; path = Classes/PGPlugin.m; sourceTree = "<group>"; };
30E563CD13E217EC00C949AA /* NSMutableArray+QueueAdditions.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = "NSMutableArray+QueueAdditions.h"; path = "Classes/NSMutableArray+QueueAdditions.h"; sourceTree = "<group>"; };
@@ -278,6 +284,8 @@
888700D710922F56009987E8 /* Commands */ = {
isa = PBXGroup;
children = (
+ 30C684921407044A004C1A8E /* PGURLProtocol.h */,
+ 30C684931407044A004C1A8E /* PGURLProtocol.m */,
30C6847E1406CB38004C1A8E /* PGWhitelist.h */,
30C6847F1406CB38004C1A8E /* PGWhitelist.m */,
1F2BECBE13F9785B00A93BF6 /* Battery.h */,
@@ -418,6 +426,7 @@
30C684811406CB38004C1A8E /* PGWhitelist.h in Headers */,
30B39EC013D0268B0009682A /* PGSplashScreen.h in Headers */,
30E563D113E217EC00C949AA /* NSMutableArray+QueueAdditions.h in Headers */,
+ 30C684951407044B004C1A8E /* PGURLProtocol.h in Headers */,
);
runOnlyForDeploymentPostprocessing = 0;
};
@@ -458,6 +467,7 @@
30E563CF13E217EC00C949AA /* NSMutableArray+QueueAdditions.h in Headers */,
1F2BECC013F9785B00A93BF6 /* Battery.h in Headers */,
30C684801406CB38004C1A8E /* PGWhitelist.h in Headers */,
+ 30C684941407044B004C1A8E /* PGURLProtocol.h in Headers */,
);
runOnlyForDeploymentPostprocessing = 0;
};
@@ -620,6 +630,7 @@
30B39EC113D0268B0009682A /* PGSplashScreen.m in Sources */,
30E563D213E217EC00C949AA /* NSMutableArray+QueueAdditions.m in Sources */,
30C684831406CB38004C1A8E /* PGWhitelist.m in Sources */,
+ 30C684971407044B004C1A8E /* PGURLProtocol.m in Sources */,
);
runOnlyForDeploymentPostprocessing = 0;
};
@@ -658,6 +669,7 @@
30E563D013E217EC00C949AA /* NSMutableArray+QueueAdditions.m in Sources */,
1F2BECC113F9785B00A93BF6 /* Battery.m in Sources */,
30C684821406CB38004C1A8E /* PGWhitelist.m in Sources */,
+ 30C684961407044B004C1A8E /* PGURLProtocol.m in Sources */,
);
runOnlyForDeploymentPostprocessing = 0;
};
Please sign in to comment.
Something went wrong with that request. Please try again.