blob: 31934c17841dc1436295683bd8eb11a7e5646722 [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
{
public class PluginConfig
{
public PluginConfig(string name, bool autoLoad = false)
{
Name = name;
isAutoLoad = autoLoad;
}
public string Name;
public bool isAutoLoad;
}
protected Dictionary<string, PluginConfig> AllowedPlugins;
protected List<string> AllowedDomains;
protected Dictionary<string, string> Preferences;
public string ContentSrc { get; private set; }
protected bool AllowAllDomains = false;
protected bool AllowAllPlugins = false;
public ConfigHandler()
{
AllowedPlugins = new Dictionary<string, PluginConfig>();
AllowedDomains = new List<string>();
Preferences = new Dictionary<string, string>();
}
public string GetPreference(string key)
{
return Preferences[key];
}
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.Keys.Contains(key);
}
private void LoadPluginFeatures(XDocument document)
{
var plugins = from results in document.Descendants("plugin")
select new
{
name = (string)results.Attribute("name"),
autoLoad = results.Attribute("onload")
};
foreach (var plugin in plugins)
{
Debug.WriteLine("Warning: Deprecated use of <plugin> by plugin : " + plugin.name);
PluginConfig pConfig = new PluginConfig(plugin.name, plugin.autoLoad != null && plugin.autoLoad.Value == "true");
if (pConfig.Name == "*")
{
AllowAllPlugins = true;
// break; wait, don't, some still could be autoload
}
else
{
AllowedPlugins[pConfig.Name] = pConfig;
}
}
var features = document.Descendants("feature");
foreach (var feature in features)
{
var name = feature.Attribute("name");
var values = from results in feature.Descendants("param")
where ((string)results.Attribute("name") == "wp-package")
select results;
var value = values.FirstOrDefault();
if (value != null)
{
string key = (string)value.Attribute("value");
Debug.WriteLine("Adding feature.value=" + key);
var onload = value.Attribute("onload");
PluginConfig pConfig = new PluginConfig(key, onload != null && onload.Value == "true");
AllowedPlugins[key] = pConfig;
}
}
}
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());
LoadPluginFeatures(document);
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)
{
Preferences[pref.name] = pref.value;
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);
}
var contentsTag = document.Descendants("content").FirstOrDefault();
if (contentsTag != null)
{
var src = contentsTag.Attribute("src");
ContentSrc = (string)src.Value;
}
}
else
{
// no config.xml, allow all
AllowAllDomains = true;
AllowAllPlugins = true;
}
}
}
}