Updated Branches:
  refs/heads/custom_schemes [created] 4af27beff

.


Project: http://git-wip-us.apache.org/repos/asf/cordova-ios/repo
Commit: http://git-wip-us.apache.org/repos/asf/cordova-ios/commit/4af27bef
Tree: http://git-wip-us.apache.org/repos/asf/cordova-ios/tree/4af27bef
Diff: http://git-wip-us.apache.org/repos/asf/cordova-ios/diff/4af27bef

Branch: refs/heads/custom_schemes
Commit: 4af27beffc410639acea7da07dcc0ea1f0b109d3
Parents: 5e8e269
Author: Michal Mocny <[email protected]>
Authored: Fri Apr 12 17:00:05 2013 -0400
Committer: Michal Mocny <[email protected]>
Committed: Fri Apr 12 17:00:05 2013 -0400

----------------------------------------------------------------------
 CordovaLib/Classes/CDVURLProtocol.m |    8 +--
 CordovaLib/Classes/CDVWhitelist.h   |    5 +-
 CordovaLib/Classes/CDVWhitelist.m   |   95 ++++++++++++++++++++----------
 3 files changed, 66 insertions(+), 42 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/cordova-ios/blob/4af27bef/CordovaLib/Classes/CDVURLProtocol.m
----------------------------------------------------------------------
diff --git a/CordovaLib/Classes/CDVURLProtocol.m 
b/CordovaLib/Classes/CDVURLProtocol.m
index afc10de..bc9fa95 100644
--- a/CordovaLib/Classes/CDVURLProtocol.m
+++ b/CordovaLib/Classes/CDVURLProtocol.m
@@ -133,12 +133,8 @@ static CDVViewController 
*viewControllerForRequest(NSURLRequest* request)
             // For this reason, we return NO when cmds exist.
             return !hasCmds;
         }
-        // we only care about http and https connections.
-        // CORS takes care of http: trying to access file: URLs.
-        if ([gWhitelist schemeIsAllowed:[theUrl scheme]]) {
-            // if it FAILS the whitelist, we return TRUE, so we can fail the 
connection later
-            return ![gWhitelist URLIsAllowed:theUrl];
-        }
+
+        return ![gWhitelist URLIsAllowed:theUrl];
     }
 
     return NO;

http://git-wip-us.apache.org/repos/asf/cordova-ios/blob/4af27bef/CordovaLib/Classes/CDVWhitelist.h
----------------------------------------------------------------------
diff --git a/CordovaLib/Classes/CDVWhitelist.h 
b/CordovaLib/Classes/CDVWhitelist.h
index 3741e94..e339dd0 100644
--- a/CordovaLib/Classes/CDVWhitelist.h
+++ b/CordovaLib/Classes/CDVWhitelist.h
@@ -23,14 +23,11 @@ extern NSString* const kCDVDefaultWhitelistRejectionString;
 
 @interface CDVWhitelist : NSObject
 
-@property (nonatomic, readonly, strong) NSArray* whitelist;
-@property (nonatomic, readonly, strong) NSArray* expandedWhitelist;
-@property (nonatomic, readonly, assign) BOOL allowAll;
 @property (nonatomic, copy) NSString* whitelistRejectionFormatString;
 
 - (id)initWithArray:(NSArray*)array;
-- (BOOL)URLIsAllowed:(NSURL*)url;
 - (BOOL)schemeIsAllowed:(NSString*)scheme;
+- (BOOL)URLIsAllowed:(NSURL*)url;
 - (NSString*)errorStringForURL:(NSURL*)url;
 
 @end

http://git-wip-us.apache.org/repos/asf/cordova-ios/blob/4af27bef/CordovaLib/Classes/CDVWhitelist.m
----------------------------------------------------------------------
diff --git a/CordovaLib/Classes/CDVWhitelist.m 
b/CordovaLib/Classes/CDVWhitelist.m
index 77e20ac..db7aa32 100644
--- a/CordovaLib/Classes/CDVWhitelist.m
+++ b/CordovaLib/Classes/CDVWhitelist.m
@@ -20,12 +20,12 @@
 #import "CDVWhitelist.h"
 
 NSString* const kCDVDefaultWhitelistRejectionString = @"ERROR whitelist 
rejection: url='%@'";
+NSString* const kCDVDefaultSchemeName = @"cdv-default-scheme";
 
 @interface CDVWhitelist ()
 
 @property (nonatomic, readwrite, strong) NSArray* whitelist;
-@property (nonatomic, readwrite, strong) NSArray* expandedWhitelist;
-@property (nonatomic, readwrite, assign) BOOL allowAll;
+@property (nonatomic, readwrite, strong) NSDictionary* expandedWhitelists;
 
 - (void)processWhitelist;
 
@@ -33,15 +33,14 @@ NSString* const kCDVDefaultWhitelistRejectionString = 
@"ERROR whitelist rejectio
 
 @implementation CDVWhitelist
 
-@synthesize whitelist, expandedWhitelist, allowAll, 
whitelistRejectionFormatString;
+@synthesize whitelist, expandedWhitelists, whitelistRejectionFormatString;
 
 - (id)initWithArray:(NSArray*)array
 {
     self = [super init];
     if (self) {
         self.whitelist = array;
-        self.expandedWhitelist = nil;
-        self.allowAll = NO;
+        self.expandedWhitelists = nil;
         self.whitelistRejectionFormatString = 
kCDVDefaultWhitelistRejectionString;
         [self processWhitelist];
     }
@@ -94,6 +93,17 @@ NSString* const kCDVDefaultWhitelistRejectionString = 
@"ERROR whitelist rejectio
     }
 }
 
+- (NSString*)extractSchemeFromUrlString:(NSString*)url
+{
+    NSURL* aUrl = [NSURL URLWithString:url];
+
+    if ((aUrl != nil) && ([aUrl scheme] != nil)) { // found scheme
+        return [aUrl scheme];
+    } else {
+        return kCDVDefaultSchemeName;
+    }
+}
+
 - (void)processWhitelist
 {
     if (self.whitelist == nil) {
@@ -101,70 +111,91 @@ NSString* const kCDVDefaultWhitelistRejectionString = 
@"ERROR whitelist rejectio
         return;
     }
 
-    NSMutableArray* expanded = [NSMutableArray 
arrayWithCapacity:[self.whitelist count]];
-
-    // iterate through settings ExternalHosts, check for equality
-    NSEnumerator* enumerator = [self.whitelist objectEnumerator];
-    id externalHost = nil;
+    NSMutableDictionary* _expandedWhitelists = [@{kCDVDefaultSchemeName: 
[NSMutableArray array]} mutableCopy];
 
     // only allow known TLDs (since Aug 23rd 2011), and two character country 
codes
     // does not match internationalized domain names with non-ASCII characters
     NSString* tld_match = 
@"(aero|asia|arpa|biz|cat|com|coop|edu|gov|info|int|jobs|mil|mobi|museum|name|net|org|pro|tel|travel|xxx|[a-z][a-z])";
 
-    while (externalHost = [enumerator nextObject]) {
-        NSString* regex = [self extractHostFromUrlString:externalHost];
-        BOOL is_ip = [self isIPv4Address:regex];
+    // iterate through settings ExternalHosts, check for equality
+    for (NSString* externalHost in self.whitelist) {
+        NSString* host = [self extractHostFromUrlString:externalHost];
+        NSString* scheme = [self extractSchemeFromUrlString:externalHost];
 
         // check for single wildcard '*', if found set allowAll to YES
-        if ([regex isEqualToString:@"*"]) {
-            self.allowAll = YES;
-            self.expandedWhitelist = [NSArray arrayWithObject:regex];
-            break;
+        if ([host isEqualToString:@"*"]) {
+            [_expandedWhitelists setObject:[NSArray arrayWithObject:host] 
forKey:scheme];
+            continue;
+        }
+
+        // if this is the first value for this scheme, create a new entry
+        if ([_expandedWhitelists objectForKey:scheme] == nil) {
+            [_expandedWhitelists setObject:[NSMutableArray array] 
forKey:scheme];
         }
 
         // starts with wildcard match - we make the first '.' optional (so 
'*.org.apache.cordova' will match 'org.apache.cordova')
         NSString* prefix = @"*.";
-        if ([regex hasPrefix:prefix]) {
+        if ([host hasPrefix:prefix]) {
             // replace the first two characters '*.' with our regex
-            regex = [regex stringByReplacingCharactersInRange:NSMakeRange(0, 
[prefix length]) withString:@"(\\s{0}|*.)"]; // the '*' and '.' will be 
substituted later
+            host = [host stringByReplacingCharactersInRange:NSMakeRange(0, 
[prefix length]) withString:@"(\\s{0}|*.)"]; // the '*' and '.' will be 
substituted later
         }
 
         // ends with wildcard match for TLD
-        if (!is_ip && [regex hasSuffix:@".*"]) {
+        if (![self isIPv4Address:host] && [host hasSuffix:@".*"]) {
             // replace * with tld_match
-            regex = [regex 
stringByReplacingCharactersInRange:NSMakeRange([regex length] - 1, 1) 
withString:tld_match];
+            host = [host stringByReplacingCharactersInRange:NSMakeRange([host 
length] - 1, 1) withString:tld_match];
         }
         // escape periods - since '.' means any character in regex
-        regex = [regex stringByReplacingOccurrencesOfString:@"." 
withString:@"\\."];
+        host = [host stringByReplacingOccurrencesOfString:@"." 
withString:@"\\."];
         // wildcard is match 1 or more characters (to make it simple, since we 
are not doing verification whether the hostname is valid)
-        regex = [regex stringByReplacingOccurrencesOfString:@"*" 
withString:@".*"];
+        host = [host stringByReplacingOccurrencesOfString:@"*" 
withString:@".*"];
 
-        [expanded addObject:regex];
+        [[_expandedWhitelists objectForKey:scheme] addObject:host];
     }
 
-    self.expandedWhitelist = expanded;
+    self.expandedWhitelists = _expandedWhitelists;
 }
 
 - (BOOL)schemeIsAllowed:(NSString*)scheme
 {
-    return [scheme isEqualToString:@"http"] ||
-           [scheme isEqualToString:@"https"] ||
-           [scheme isEqualToString:@"ftp"] ||
-           [scheme isEqualToString:@"ftps"];
+    if ([scheme isEqualToString:@"http"] ||
+        [scheme isEqualToString:@"https"] ||
+        [scheme isEqualToString:@"ftp"] ||
+        [scheme isEqualToString:@"ftps"]) {
+        return YES;
+    }
+
+    return (self.expandedWhitelists != nil) && ([self.expandedWhitelists 
objectForKey:scheme] != nil);
 }
 
 - (BOOL)URLIsAllowed:(NSURL*)url
 {
-    if (self.expandedWhitelist == nil) {
+    NSString* scheme = [url scheme];
+
+    // http[s] and ftp[s] should also validate against the common set in the 
kCDVDefaultSchemeName list
+    if ([scheme isEqualToString:@"http"] || [scheme isEqualToString:@"https"] 
|| [scheme isEqualToString:@"ftp"] || [scheme isEqualToString:@"ftps"]) {
+        NSURL* newUrl = [NSURL URLWithString:[NSString 
stringWithFormat:@"%@://%@", kCDVDefaultSchemeName, [url host]]];
+        // If it is allowed, we are done.  If not, continue to check for the 
actual scheme-specific list
+        if ([self URLIsAllowed:newUrl]) {
+            return YES;
+        }
+    }
+
+    // Check that the scheme is supported
+    if (![self schemeIsAllowed:scheme]) {
         return NO;
     }
 
-    if (self.allowAll) {
+    NSArray* expandedWhitelist = [self.expandedWhitelists objectForKey:scheme];
+
+    // Are we allowing everything for this scheme?
+    // TODO: consider just having a static sentinel value for the "allow all" 
list, so we can use object equality
+    if (([expandedWhitelist count] == 1) && [[expandedWhitelist 
objectAtIndex:0] isEqualToString:@"*"]) {
         return YES;
     }
 
     // iterate through settings ExternalHosts, check for equality
-    NSEnumerator* enumerator = [self.expandedWhitelist objectEnumerator];
+    NSEnumerator* enumerator = [expandedWhitelist objectEnumerator];
     id regex = nil;
     NSString* urlHost = [url host];
 

Reply via email to