blob: d90e9b5e0d03a97ac986865a8028534f734e224c [file] [log] [blame]
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.IO;
using System.Linq;
using System.Text;
using System.Text.RegularExpressions;
using System.Windows;
using System.Windows.Resources;
using System.Xml.Linq;
namespace WPCordovaClassLib.CordovaLib
{
class ConfigHandler
{
protected List<string> AllowedPlugins;
protected List<string> AllowedDomains;
protected Dictionary<string, string> Preferences;
protected bool AllowAllDomains = false;
protected bool AllowAllPlugins = false;
public ConfigHandler()
{
AllowedPlugins = new List<string>();
AllowedDomains = new List<string>();
Preferences = new Dictionary<string, string>();
}
public string GetPreference(string key)
{
return Preferences[key];
}
/*
- (BOOL)URLIsAllowed:(NSURL*)url
{
if (self.expandedWhitelist == nil) {
return NO;
}
if (self.allowAll) {
return YES;
}
// iterate through settings ExternalHosts, check for equality
NSEnumerator* enumerator = [self.expandedWhitelist objectEnumerator];
id regex = nil;
NSString* urlHost = [url host];
// if the url host IS found in the whitelist, load it in the app (however UIWebViewNavigationTypeOther kicks it out to Safari)
// if the url host IS NOT found in the whitelist, we do nothing
while (regex = [enumerator nextObject]) {
NSPredicate* regex_test = [NSPredicate predicateWithFormat:@"SELF MATCHES %@", regex];
if ([regex_test evaluateWithObject:urlHost] == YES) {
// if it matches at least one rule, return
return YES;
}
}
NSLog(@"%@", [self errorStringForURL:url]);
// if we got here, the url host is not in the white-list, do nothing
return NO;
}*/
protected static string[] AllowedSchemes = {"http","https","ftp","ftps"};
protected bool SchemeIsAllowed(string scheme)
{
return AllowedSchemes.Contains(scheme);
}
protected string PathAndQuery(Uri uri)
{
string result = uri.LocalPath;
if (uri.Query.Length > 0)
{
result += uri.Query;
}
return result;
}
protected void AddWhiteListEntry(string origin, bool allowSubdomains)
{
if (origin == "*")
{
AllowAllDomains = true;
}
if (AllowAllDomains)
{
return;
}
string hostMatchingRegex = "";
string hostName;
try
{
Uri uri = new Uri(origin.Replace("*", "replaced-text"), UriKind.Absolute);
string tempHostName = uri.Host.Replace("replaced-text", "*");
//if (uri.HostNameType == UriHostNameType.Dns){}
// starts with wildcard match - we make the first '.' optional (so '*.org.apache.cordova' will match 'org.apache.cordova')
if (tempHostName.StartsWith("*."))
{ //"(\\s{0}|*.)"
hostName = @"\w*.*" + tempHostName.Substring(2).Replace(".", @"\.").Replace("*", @"\w*");
}
else
{
hostName = tempHostName.Replace(".", @"\.").Replace("*", @"\w*");
}
// "^https?://"
hostMatchingRegex = uri.Scheme + "://" + hostName + PathAndQuery(uri);
//Debug.WriteLine("Adding regex :: " + hostMatchingRegex);
AllowedDomains.Add(hostMatchingRegex);
}
catch (Exception)
{
Debug.WriteLine("Invalid Whitelist entry (probably missing the protocol):: " + origin);
}
}
/**
An access request is granted for a given URI if there exists an item inside the access-request list such that:
- The URI's scheme component is the same as scheme; and
- if subdomains is false or if the URI's host component is not a domain name (as defined in [RFC1034]), the URI's host component is the same as host; or
- if subdomains is true, the URI's host component is either the same as host, or is a subdomain of host (as defined in [RFC1034]); and
- the URI's port component is the same as port.
**/
public bool URLIsAllowed(string url)
{
// easy case first
if (AllowAllDomains )
{
return true;
}
else
{
// start simple
Uri uri = new Uri(url,UriKind.RelativeOrAbsolute);
if (uri.IsAbsoluteUri)
{
if (this.SchemeIsAllowed(uri.Scheme))
{
// additional test because our pattern will always have a trailing '/'
string matchUrl = url;
if (PathAndQuery(uri) == "/")
{
matchUrl = url + "/";
}
foreach (string pattern in AllowedDomains)
{
if (Regex.IsMatch(matchUrl, pattern))
{
// make sure it is at the start, and not part of the query string
// special case :: http://some.other.domain/page.html?x=1&g=http://build.apache.org/
if ( Regex.IsMatch(uri.Scheme + "://" + uri.Host + "/", pattern) ||
(!Regex.IsMatch(PathAndQuery(uri), pattern)))
{
return true;
}
}
}
}
}
else
{
return true;
}
}
return false;
}
public bool IsPluginAllowed(string key)
{
return AllowAllPlugins || AllowedPlugins.Contains(key);
}
public void LoadAppPackageConfig()
{
StreamResourceInfo streamInfo = Application.GetResourceStream(new Uri("config.xml", UriKind.Relative));
if (streamInfo != null)
{
StreamReader sr = new StreamReader(streamInfo.Stream);
//This will Read Keys Collection for the xml file
XDocument document = XDocument.Parse(sr.ReadToEnd());
var plugins = from results in document.Descendants("plugin")
select new { name = (string)results.Attribute("name") };
foreach (var plugin in plugins)
{
Debug.WriteLine("plugin " + plugin.name);
if (plugin.name == "*")
{
AllowAllPlugins = true;
break;
}
else
{
AllowedPlugins.Add(plugin.name);
}
}
var preferences = from results in document.Descendants("preference")
select new
{
name = (string)results.Attribute("name"),
value = (string)results.Attribute("value")
};
foreach (var pref in preferences)
{
Debug.WriteLine("pref" + pref.name + ", " + pref.value);
}
var accessList = from results in document.Descendants("access")
select new
{
origin = (string)results.Attribute("origin"),
subdomains = (string)results.Attribute("subdomains") == "true"
};
foreach (var accessElem in accessList)
{
AddWhiteListEntry(accessElem.origin, accessElem.subdomains);
}
}
else
{
// no config.xml, allow all
AllowAllDomains = true;
AllowAllPlugins = true;
}
}
}
}