blob: e2575f72e3d1c5f84e519a46afccc9e9a0ec6038 [file] [log] [blame]
/*
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
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, string className = "")
{
Name = name;
isAutoLoad = autoLoad;
ClassName = className;
}
public string Name;
public bool isAutoLoad;
public string ClassName;
}
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.ContainsKey(key.ToLowerInvariant()) ? Preferences[key.ToLowerInvariant()] : null;
}
protected static string[] AllowedSchemes = { "http", "https", "ftp", "ftps" };
protected bool SchemeIsAllowed(string scheme)
{
return AllowedSchemes.Contains(scheme);
}
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 + uri.PathAndQuery;
//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 (this.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 (uri.PathAndQuery == "/")
{
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(uri.PathAndQuery, pattern)))
{
return true;
}
}
}
}
}
else
{
return true;
}
}
return false;
}
public string GetNamespaceForCommand(string key)
{
if(AllowedPlugins.Keys.Contains(key))
{
return AllowedPlugins[key].Name;
}
return "";
}
public bool IsPluginAllowed(string key)
{
return AllowAllPlugins || AllowedPlugins.Keys.Contains(key);
}
public string[] AutoloadPlugins
{
get
{
// TODO:
var res = from results in AllowedPlugins.TakeWhile(p => p.Value.isAutoLoad)
select results.Value.Name;
return res.ToArray<string>();
}
}
private void LoadPluginFeatures(XDocument document)
{
var features = from feats in document.Descendants()
where feats.Name.LocalName == "feature"
select feats;
foreach (var feature in features)
{
string name = (string)feature.Attribute("name");
var value = (from results in feature.Descendants()
where results.Name.LocalName == "param" && ((string)results.Attribute("name") == "wp-package")
select results).FirstOrDefault();
var autoloadNode = (from results in feature.Descendants()
where results.Name.LocalName == "param" && ((string)results.Attribute("name") == "onload")
select results).FirstOrDefault();
bool isAutoLoad = false;
if (autoloadNode != null)
{
isAutoLoad = ((string)autoloadNode.Attribute("value") == "true");
}
if (value != null)
{
string key = (string)value.Attribute("value");
Debug.WriteLine("Adding feature.value=" + key);
PluginConfig pConfig = new PluginConfig(key, isAutoLoad);
AllowedPlugins[name] = 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()
where results.Name.LocalName == "preference"
select new
{
name = (string)results.Attribute("name"),
value = (string)results.Attribute("value")
};
foreach (var pref in preferences)
{
Preferences[pref.name.ToLowerInvariant()] = pref.value;
}
var accessList = from results in document.Descendants()
where results.Name.LocalName == "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 = (from results in document.Descendants()
where results.Name.LocalName == "content"
select results).FirstOrDefault();
if (contentsTag != null)
{
var src = contentsTag.Attribute("src");
ContentSrc = (string)src.Value;
}
}
else
{
// no config.xml, allow all
AllowAllDomains = true;
AllowAllPlugins = true;
}
}
}
}