adding sharing support
authorDave Raggett <dsr@w3.org>
Fri, 29 Apr 2011 13:34:41 +0100
changeset 4 82ee4f6c2058
parent 3 f0a5da9e4150
child 5 0f4d18d55a42
adding sharing support
sharing/cat-globe.png
sharing/credentials
sharing/index.html
sharing/logo.png
sharing/p3p.html
sharing/p3p.js
sharing/p3p.xml
sharing/phpinfo.php
sharing/query.css
sharing/query.js
sharing/query.php
sharing/share.php
sharing/site.php
sharing/stucco.jpg
Binary file sharing/cat-globe.png has changed
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/sharing/credentials	Fri Apr 29 13:34:41 2011 +0100
@@ -0,0 +1,1 @@
+userid:password
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/sharing/index.html	Fri Apr 29 13:34:41 2011 +0100
@@ -0,0 +1,76 @@
+<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en-US" lang="en-US">
+<head>
+<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
+<title>Query Privacy Dashboard Data on Websites</title>
+<meta http-equiv="X-UA-Compatible" content="chrome=1" />
+<link rel="stylesheet" href="query.css" type="text/css" />
+<script type="text/javascript" src="query.js"></script>
+</head>
+<body>
+<h1><img src="cat-globe.png" /> Query Privacy Dashboard Data on Websites</h1>
+
+<div id="query_pane">
+<label for="query" title="pick which query you want to make">1. Select query</label>
+<select id="query" title="pick which query you want to make">
+<optgroup label=" ">
+<option value="0">Which websites use long lasting cookies?</option>
+<option value="1">Which websites use session cookies?</option>
+<option value="2">Which websites use flash cookies?</option>
+<option value="3">Which websites use DOM storage?</option>
+<option value="4">Which websites use invisible images?</option>
+<option value="5">Which websites use HTML5 ping attributes?</option>
+</optgroup>
+<optgroup label=" ">
+<option value="6">Which websites provide P3P privacy policies?</option>
+<option value="7">Which websites are 3rd parties?</option>
+<option value="8">Which websites use a given 3rd party?</option>
+</optgroup>
+<optgroup label=" ">
+<option value="99">What information is available on a given website?</option>
+<option value="9">Which internal 3rd parties are used by a given website?</option>
+<option value="10">Which external 3rd parties are used by a given website?</option>
+<option value="11">What cookies are used by a given domain?</option>
+<option value="12">Which websites have permission to access someones location?</option>
+</optgroup>
+
+</select>
+<br />
+
+<label id="param_caption" for="param" class="inactive">2. Query parameter</label>
+<input id="param" disabled="true" value=""><br />
+<button id="backward" disabled="true"
+ title="go back a query" class="inactive">&#9664;</button>
+<button id="forward" disabled="true"
+ title="go forward a query" class="inactive">&#9654;</button>
+<button id="execute" title="execute query against database">3. Execute query</button>
+<button id="site_info" disabled="true"
+ title="display site properties">Site information</button>
+</div>
+
+<div id="intro">
+<p>Have you ever wondered how websites are tracking you? For every
+site that you see there are several hidden sites in the background.
+Explore the dark side of the web and the host of sites used for 
+content distribution, advertising and analytics. Query the data 
+collected by the Privacy Dashbot or shared by volunteers who have 
+opted into sharing data from the Privacy Dashboard browser 
+extension.</p> 
+</div>
+
+<div id="results">
+<p class="slim">The results appear below here, click on entry to
+copy it to query parameter field. You can then click "site information"
+or select another query from the drop down menu. Use the back and
+forward buttons in the query pane to browse through your history
+of queries.</p>
+<table id="table" border="1" cellspacing="0">
+</table>
+</div>
+
+<div id="footer">
+<p>This work was made possible with funding from the European Union
+as part of the <a href="http://www.primelife.eu">PrimeLife Project</a>.</p>
+<p class="smaller">Copyright &copy; 2011 W3C (MIT, ERCIM, Keio)</p>
+</div>
+</body>
+</html>
Binary file sharing/logo.png has changed
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/sharing/p3p.html	Fri Apr 29 13:34:41 2011 +0100
@@ -0,0 +1,21 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" 
+ "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
+<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en-US" lang="en-US">
+<head>
+<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
+
+<title>P3P Test Page</title>
+<script type="text/javascript" src="p3p.js"></script>
+<style type="text/css" media="screen">
+body {
+ margin: 2em;
+}
+ul.long li { font-weight: bold }
+ul.long li span { font-weight: normal }
+</style>
+</head>
+<body>
+<div id="contact"></div>
+</body>
+</html>
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/sharing/p3p.js	Fri Apr 29 13:34:41 2011 +0100
@@ -0,0 +1,535 @@
+window.onload = start;
+
+
+function start()
+{
+  dashboard_p3p.get_policy("http://localhost/w3c/bp.xml", "/",
+    dashboard_p3p.find_applicable_policy);
+}
+
+var dashboard_p3p = {
+  get_policy: function(policy_uri, path, handler) {
+    var req = new XMLHttpRequest();
+
+    req.open("GET", policy_uri, true);
+    req.onreadystatechange = function (evt) {
+
+      if (req.readyState == 4)
+      {
+        if (req.status == 200)
+          handler(path, req);
+      }
+    };
+    req.send(null);
+  },
+
+// from XUL overlay, we can access req.channel.URI.resolve(rel_url)
+// but not from regular web page script, so we use hack for now
+
+  find_applicable_policy: function (path, req) {
+    var root = req.responseXML.documentElement;
+    var policy_refs = root.getElementsByTagName("POLICY-REF");
+
+    if (policy_refs && policy_refs.length > 0)
+    {
+      var uri = policy_refs[0].getAttribute("about");
+      var hash = uri.indexOf("#");
+
+      if (hash >= 0)
+        uri = uri.substr(0, hash);
+
+      uri = "http://localhost/w3c/" + uri;      
+
+      dashboard_p3p.get_policy(uri, path,
+         dashboard_p3p.find_applicable_policy);
+    }
+    else
+    {
+      // otherwise render policy
+      dashboard_p3p.render_policy(path, root);
+    }
+  },
+
+  render_policy: function (path, root) {
+    var p3p = dashboard_p3p;
+
+    var policies = root.getElementsByTagName("POLICY");
+    var policy = policies ? policies[0] : null;
+
+    if (!policy)
+      return;
+
+    // use server's own rendering of policy
+    if (false)
+    {
+       var discuri = policy.getAttribute("discuri");
+
+       if (discuri)
+       {
+         location.href = discuri;
+         return;
+       }
+    }
+
+    // deal with contact info
+    var contact = p3p.get_contact_group(policy);
+    p3p.dump_contact(contact, "contact");
+
+    // deal with access info
+    var access = policy.getElementsByTagName("ACCESS");
+
+    if (access && access.length > 0)
+      access = access[0];
+
+    // deal with dispute info
+    // hmm, let's ignore this for now
+
+    // deal with statements
+    var statements = policy.getElementsByTagName("STATEMENT");
+    for (var i = 0; i < statements.length; ++i)
+      p3p.dump_statement(statements[i]);
+  },
+
+  get_contact_group: function (policy) {
+    var ents = policy.getElementsByTagName("ENTITY");
+  
+    if (ents && ents.length > 0)
+    {
+      var dg = ents[0].getElementsByTagName("DATA-GROUP");
+ 
+      if (dg && dg.length > 0)
+        return dg[0];
+    }
+
+    return null;
+  },
+
+  dump_contact: function (contact, id) {
+    var obj = {};
+
+    for (var data = contact.firstChild; data; data = data.nextSibling)
+    {
+      if (data.nodeType == 1)
+      {
+        var ref = data.getAttribute("ref");
+        var value = data.firstChild.nodeValue;
+        this.analyse_info(obj, ref, value);
+      }
+    }
+
+    var div = document.getElementById(id);
+    var s = "";
+
+    s += "<h2>"+obj.business.name+" Privacy Policy</h2>\n<p>\n";
+
+    s += obj.business.contact_info.postal.street + "<br />\n";
+    s += obj.business.contact_info.postal.city + ", ";
+
+    if (obj.business.contact_info.postal.stateprov)
+      s += obj.business.contact_info.postal.stateprov + " ";
+  
+    if (obj.business.contact_info.postal.postalcode)
+      s += obj.business.contact_info.postal.postalcode + "<br />\n";
+
+    s += obj.business.contact_info.postal.country + "<br />\n";
+
+    if (obj.business.contact_info.online.email)
+    {
+      s += "<br \>email: \n";
+      s += obj.business.contact_info.online.email;
+    }
+
+    if (obj.business.contact_info.telecom.telephone)
+    {
+      s += "<br \>phone: \n";
+      if (obj.business.contact_info.telecom.telephone.intcode)
+      {
+        s += "+"  + obj.business.contact_info.telecom.telephone.intcode;
+        s += "."  + obj.business.contact_info.telecom.telephone.loccode;
+        s += "."  + obj.business.contact_info.telecom.telephone.number;
+      }
+      else
+      {
+         if (obj.business.contact_info.telecom.telephone.substr(0,2) == "00")
+           s += "+" + obj.business.contact_info.telecom.telephone.substr(2);
+         else
+           s += obj.business.contact_info.telecom.telephone;
+      }
+    }
+
+    s += "\n</p>\n";
+
+    div.innerHTML += s;
+  },
+
+  // map ref string into object tree
+  analyse_info: function (obj, ref, value) {
+    ref = ref.substr(1).split(".");
+
+    var part = obj;
+    var name;
+
+    for (var i = 0; i < ref.length - 1; ++i)
+    {
+      name = ref[i];
+      name = name.replace(/-/g, "_");
+
+      if (!part[name])
+        part[name] = {};
+
+      part = part[name];
+    }
+
+    name = ref[ref.length - 1];
+    part[name] = value;
+  },
+
+  dump_statement: function (statement) {
+    var div = document.createElement("div");
+
+    var p = document.createElement("p");
+    p.innerHTML = this.get_consequence(statement);
+    div.appendChild(p);
+
+    p = document.createElement("p");
+    p.innerHTML = "The follow kinds of data are collected";
+    div.appendChild(p); 
+
+    var ul = document.createElement("ul");
+    div.appendChild(ul); 
+
+    var el = statement.getElementsByTagName("DATA-GROUP");
+
+    if (el && el.length > 0)
+    {
+      var data = el[0].getElementsByTagName("DATA");
+      var li;
+      var desc;
+
+      for (var i = 0; i < data.length; ++i)
+      {
+        var ref = data[i].getAttribute("ref").substr(1);
+        var desc = this.get_description(ref);
+        if (!desc) desc = ref;
+        li = document.createElement("li");
+        li.innerHTML = desc;
+        ul.appendChild(li);
+      }
+    }
+
+    p = document.createElement("p");
+    p.innerHTML = "This data is used for";
+    div.appendChild(p); 
+
+    var ul = document.createElement("ul");
+    ul.className = "long";
+    div.appendChild(ul); 
+
+    el = statement.getElementsByTagName("PURPOSE");
+
+    if (el && el.length > 0)
+    {
+      for (el = el[0].firstChild; el; el = el.nextSibling)
+      {
+        if (el.nodeType != 1)
+          continue;
+
+        var purpose = this.purposes[el.nodeName];
+        if (!purpose) purpose = el.nodeName;
+
+        var li = document.createElement("li");
+        li.innerHTML = purpose+this.opt_in_out(el);
+        ul.appendChild(li);
+      }
+    }
+
+    p = document.createElement("p");
+    p.innerHTML = "This data is used by";
+    div.appendChild(p); 
+
+    var ul = document.createElement("ul");
+    ul.className = "long";
+    div.appendChild(ul); 
+
+    el = statement.getElementsByTagName("RECIPIENT");
+
+    if (el && el.length > 0)
+    {
+      for (el = el[0].firstChild; el; el = el.nextSibling)
+      {
+        if (el.nodeType != 1)
+          continue;
+
+        var recipient = this.recipients[el.nodeName];
+        if (!recipient) purpose = el.nodeName;
+
+        var li = document.createElement("li");
+        li.innerHTML = recipient+this.opt_in_out(el)+
+           this.recipient_description(el);
+        ul.appendChild(li);
+      }
+    }
+
+    p = document.createElement("p");
+    p.innerHTML = "Data retention:";
+    div.appendChild(p);
+
+    var ul = document.createElement("ul");
+    ul.className = "long";
+    div.appendChild(ul); 
+
+    el = statement.getElementsByTagName("RETENTION");
+
+    if (el && el.length > 0)
+    {
+      for (el = el[0].firstChild; el; el = el.nextSibling)
+      {
+        if (el.nodeType != 1)
+          continue;
+
+        var retention = this.retention[el.nodeName];
+        if (!retention) purpose = el.nodeName;
+
+        var li = document.createElement("li");
+        li.innerHTML = retention;
+        ul.appendChild(li);
+      }
+    }
+
+    document.body.appendChild(div);
+  },
+
+  opt_in_out: function (el) {
+    var req = el.getAttribute("required");
+
+    if (req == "opt-in")
+      return " (opt in)";
+
+    if (req == "opt-out")
+      return " (opt out)";
+
+    return "";
+  },
+
+  recipient_description: function (el) {
+    el = el.firstElementChild;
+
+    if (el)
+      return ", but note that " + el.firstChild.nodeValue;
+
+    return "";
+  },
+
+  get_consequence: function (statement) {
+    var el = statement.getElementsByTagName("CONSEQUENCE");
+
+    if (el && el.length > 0)
+      return el[0].firstChild.nodeValue;
+
+    return null;
+  },
+
+  purposes: {
+    "current" :
+      "Completion and Support of Activity For Which Data Was " +
+      "Provided<span>: Information may be used by the service provider " +
+      "to complete the activity for which it was provided, whether " +
+      "a one-time activity such as returning the results from a Web " +
+      "search, forwarding an email message, or placing an order; or " +
+      "a recurring activity such as providing a subscription service, " +
+      "or allowing access to an online address book or electronic " +
+      "wallet.</span>",
+    "admin" :
+      "Web Site and System Administration<span>: Information may be used " +
+      "for the technical support of the Web site and its computer " +
+      "system. This would include processing computer account " +
+      "information, information used in the course of securing and " +
+      "maintaining the site, and verification of Web site activity " +
+      "by the site or its agents.</span>",
+    "develop" :
+      "Research and Development<span>: Information may be used to " +
+      "enhance, evaluate, or otherwise review the site, service, " +
+      "product, or market. This does not include personal information " +
+      "used to tailor or modify the content to the specific individual " +
+      "nor information used to evaluate, target, profile or contact " +
+      "the individual.</span>",
+    "tailoring" :
+      "One-time Tailoring<span>: Information may be used to tailor " +
+      "or modify content or design of the site where the information " +
+      "is used only for a single visit to the site and not used for " +
+      "any kind of future customization. For example, an online store " +
+      "might suggest other items a visitor may wish to purchase based " +
+      "on the items he has already placed in his shopping basket.</span>",
+    "pseudo-analysis" :
+      "Pseudonymous Analysis<span>: Information may be used to create " +
+      "or build a record of a particular individual or computer that " +
+      "is tied to a pseudonymous identifier, without tying identified " +
+      "data (such as name, address, phone number, or email address) " +
+      "to the record. This profile will be used to determine the habits, " +
+      "interests, or other characteristics of individuals for purpose " +
+      "of research, analysis and reporting, but it will not be used to " +
+      "attempt to identify specific individuals. For example, a marketer " +
+      "may wish to understand the interests of visitors to different " +
+      "portions of a Web site.</span>",
+    "pseudo-decision" :
+      "Pseudonymous Decision<span>: Information may be used to create " +
+      "or build a record of a particular individual or computer that " +
+      "is tied to a pseudonymous identifier, without tying identified " +
+      "data (such as name, address, phone number, or email address) to " +
+      "the record. This profile will be used to determine the habits, " +
+      "interests, or other characteristics of individuals to make a " +
+      "decision that directly affects that individual, but it will not " +
+      "be used to attempt to identify specific individuals. For example, " +
+      "a marketer may tailor or modify content displayed to the browser " +
+      "based on pages viewed during previous visits.</span>",
+    "individual-analysis" :
+      "Individual Analysis<span>: Information may be used to determine " +
+      "the habits, interests, or other characteristics of individuals " +
+      "and combine it with identified data for the purpose of research, " +
+      "analysis and reporting. For example, an online Web site for a " +
+      "physical store may wish to analyze how online shoppers make " +
+      "offline purchases.</span>",
+    "individual-decision" :
+      "Individual Decision<span>:  Information may be used to determine " +
+      "the habits, interests, or other characteristics of individuals " +
+      "and combine it with identified data to make a decision that " +
+      "directly affects that individual.  For example, an online store " +
+      "suggests items a visitor may wish to purchase based on items he " +
+      "has purchased during previous visits to the Web site.</span>",
+    "contact" :
+      "Contacting Visitors for Marketing of Services or Products<span>: " +
+      "Information may be used to contact the individual, through a " +
+      "communications channel other than voice telephone, for the " +
+      "promotion of a product or service. This includes notifying " +
+      "visitors about updates to the Web site. This does not include a " +
+      "direct reply to a question or comment or customer service for a " +
+      "single transaction -- in those cases, <current/> would be used. " +
+      "In addition, this does not include marketing via customized Web " +
+      "content or banner advertisements embedded in sites the user is " +
+      "visiting.</span>",
+    "historical" :
+      "Historical Preservation<span>: Information may be archived or " +
+      "stored for the purpose of preserving social history as governed " +
+      "by an existing law or policy. This law or policy MUST be " +
+      "referenced in the <DISPUTES> element and MUST include a specific " +
+      "definition of the type of qualified researcher who can access the " +
+      "information, where this information will be stored and specifically " +
+      "how this collection advances the preservation of history.</span>",
+    "telemarketing" :
+      "Contacting Visitors for Marketing of Services or Products Via " +
+      "Telephone<span>: Information may be used to contact the individual " +
+      "via a voice telephone call for promotion of a product or service. " +
+      "This does not include a direct reply to a question or comment or " +
+      "customer service for a single transaction.</span>",
+    "other-purpose" : "Additional purposes."
+  },
+
+  recipients: {
+    "ours" :
+      "Ourselves and/or entities acting as our agents or entities for " +
+      "whom we are acting as an agent<span>: An agent in this instance " +
+      "is defined as a third party that processes data only on behalf " +
+      "of the service provider for the completion of the stated purposes. " +
+      "(e.g., the service provider and its printing bureau which prints " +
+      "address labels and does nothing further with the information.)</span>",
+    "delivery" :
+      "Delivery services possibly following different practices<span>: " +
+      "Legal entities performing delivery services that may use data for " +
+      "purposes other than completion of the stated purpose. This should " +
+      "also be used for delivery services whose data practices are " +
+      "unknown.</span>",
+    "same" :
+      "Legal entities following our practices<span>: Legal entities who " +
+      "use the data on their own behalf under equable practices. (e.g., " +
+      "consider a service provider that grants the user access to collected " +
+      "personal information, and also provides it to a partner who uses " +
+      "it once but discards it. Since the recipient, who has otherwise " +
+      "similar practices, cannot grant the user access to information " +
+      "that it discarded, they are considered to have equable " +
+      "practices.)</span>",
+    "other-recipient" :
+      "Legal entities following different practices<span>: Legal entities "+
+      "that are constrained by and accountable to the original service " +
+      "provider, but may use the data in a way not specified in the " +
+      "service provider's practices (e.g., the service provider collects " +
+      "data that is shared with a partner who may use it for other " +
+      "purposes. However, it is in the service provider's interest to " +
+      "ensure that the data is not used in a way that would be considered " +
+      "abusive to the users' and its own interests.)</span>",
+    "unrelated" :
+      "Unrelated third parties<span>: Legal entities whose data usage " +
+      "practices are not known by the original service provider.</span>",
+    "public" :
+      "Public fora<span>: Public fora such as bulletin boards, public " +
+      "directories, or commercial CD-ROM directories.</span>"
+  },
+
+  retention: {
+    "no-retention" :
+      "Information is not retained for more than a brief period of time " +
+      "necessary to make use of it during the course of a single online " +
+      "interaction. <span>Information MUST be destroyed following this " +
+      "interaction and MUST NOT be logged, archived, or otherwise stored. " +
+      "This type of retention policy would apply, for example, to services " +
+      "that keep no Web server logs, set cookies only for use during a " +
+      "single session, or collect information to perform a search but do " +
+      "not keep logs of searches performed.</span>",
+    "stated-purpose" :
+      "Information is retained to meet the stated purpose. <span>This " +
+      "requires information to be discarded at the earliest time possible. " +
+      "Sites MUST have a retention policy that establishes a destruction " +
+      "time table. The retention policy MUST be included in or linked " +
+      "from the site's human-readable privacy policy.</span>",
+    "legal-requirement" :
+      "As required by law or liability under applicable law<span>: " +
+      "Information is retained to meet a stated purpose, but the " +
+      "retention period is longer because of a legal requirement or " +
+      "liability. For example, a law may allow consumers to dispute " +
+      "transactions for a certain time period; therefore a business may " +
+      "for liability reasons decide to maintain records of transactions, " +
+      "or a law may affirmatively require a certain business to maintain " +
+      "records for auditing or other soundness purposes. Sites MUST have " +
+      "a retention policy that establishes a destruction time table. The " +
+      "retention policy MUST be included in or linked from the site's " +
+      "human-readable privacy policy.</span>",
+    "business-practices" :
+      "Determined by service provider's business practice<span>: " +
+      "Information is retained under a service provider's stated " +
+      "business practices. Sites MUST have a retention policy that " +
+      "establishes a destruction time table. The retention policy MUST " +
+      "be included in or linked from the site's human-readable privacy " +
+      "policy.</span>",
+    "indefinitely" :
+      "Indefinitely<span>: Information is retained for an indeterminate " +
+      "period of time. The absence of a retention policy would be " +
+      "reflected under this option. Where the recipient is a public " +
+      "fora, this is the appropriate retention policy.</span>"
+  },
+
+  get_description: function (name) {
+    var desc = this.data_description[name];
+    if (!desc) desc = name;
+    return desc;
+  },
+
+  data_description: {
+    "user.name" : "user's name",
+    "user.employer" : "user's employer",
+    "dynamic.clickstream" :"information typically found in Web " +
+      "server access logs, e.g.  the IP address or hostname of the user's " +
+      "computer, the URI of the resource requested, the time the request " +
+      "was made, the HTTP method used in the request, the size of the " +
+      "response, and the HTTP status code in the response.",
+    "dynamic.http" : "additional information carried in HTTP requests",
+    "dynamic.clientevents" :"information about how the user " +
+      "interacts with a web page, e.g. mouse movements and clicks",
+    "dynamic.searchtext" :"search terms entered by the user",
+    "dynamic.interactionrecord": "additional information on " +
+      "user interaction, e.g. account transactions, etc.",
+    "dynamic.cookies" :"the use of web page cookies for various " +
+      "purposes, e.g. session identifiers and status information"
+  }
+};
+
+
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/sharing/p3p.xml	Fri Apr 29 13:34:41 2011 +0100
@@ -0,0 +1,38 @@
+<POLICY xmlns="http://www.w3.org/2000/12/p3pv1"
+    discuri="http://www.blueyonderairlines.com/ourprivacypolicy.html"  
+    opturi="http://www.blueyonderairlines.com/optin.html">
+ <ENTITY>
+  <DATA-GROUP>
+   <DATA ref="#business.name">Blue Yonder Airlines</DATA>
+   <DATA ref="#business.contact-info.postal.street">3456 Main St.</DATA>
+   <DATA ref="#business.contact-info.postal.city">Tampa</DATA>
+   <DATA ref="#business.contact-info.postal.stateprov">Fl</DATA>
+   <DATA ref="#business.contact-info.postal.postalcode">77062</DATA>
+   <DATA ref="#business.contact-info.postal.country">USA</DATA>
+   <DATA ref="#business.contact-info.online.email">[email protected]</DATA>
+   <DATA ref="#business.contact-info.telecom.telephone.intcode">1</DATA>
+   <DATA ref="#business.contact-info.telecom.telephone.loccode">800</DATA>
+   <DATA ref="#business.contact-info.telecom.telephone.number">5550158</DATA>
+  </DATA-GROUP>
+ </ENTITY>
+ <ACCESS><nonident/></ACCESS>
+<STATEMENT>
+  <PURPOSE><admin/><develop/></PURPOSE>
+  <RECIPIENT><ours/></RECIPIENT>
+  <RETENTION><stated-purpose/></RETENTION>
+  <DATA-GROUP>
+    <DATA ref="#dynamic.clickstream.server"/>
+    <DATA ref="#dynamic.http.useragent"/>
+  </DATA-GROUP>
+</STATEMENT>
+<STATEMENT>
+  <PURPOSE><pseudo-analysis required="opt-in"/></PURPOSE>
+  <RECIPIENT><other-recipient/></RECIPIENT>
+  <RETENTION><indefinitely/></RETENTION>
+  <DATA-GROUP>
+    <DATA ref="#user.home-info.postal.postalcode">
+      <CATEGORIES><demographic/></CATEGORIES>
+    </DATA>
+  </DATA-GROUP>
+</STATEMENT>
+</POLICY>
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/sharing/phpinfo.php	Fri Apr 29 13:34:41 2011 +0100
@@ -0,0 +1,13 @@
+<?php
+$username = "www-data";
+$password = "nutmeg23";
+$database = "privacy-dashboard";
+
+mysql_connect(localhost,$username,$password);
+
[email protected]_select_db($database) or die( "Unable to select database");
+
+
+echo "It works";
+mysql_close();
+?>
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/sharing/query.css	Fri Apr 29 13:34:41 2011 +0100
@@ -0,0 +1,53 @@
+body {
+  background-color: #EEF;
+  background-image: url(stucco.jpg);
+  color: #000;
+}
+
+/* render line between groups of options */
+
+optgroup + optgroup { border-top: solid 1px #888; }
+
+h1 img { vertical-align: middle }
+
+#query_pane {
+  float:right;
+  right: 0;
+  width: 50%;
+  padding: 1em;
+  border: solid 1px #888;
+  background-color: #CCC;
+  line-height: 2em;
+}
+
+button { line-height: 1.2em; margin-top: 10px }
+
+#intro {
+  width: 45%;
+}
+
+#param { width: 100% }
+#site_info { float: right; }
+
+p.slim { margin-top: 0; margin-bottom: 0}
+#results {
+  padding-top: 2em;
+  clear: both;
+}
+
+#results table {
+  width: 100%;
+}
+/*
+#footer {
+ position:absolute;
+ bottom: 0;
+}
+*/
+label.inactive { color: #AAA }
+input.inactive { color: #AAA; background-color: #CCC }
+input { color: black; background-color: #EEE; padding-left: 5px }
+table { background-color: #FFFFFF; }
+thead { background-color: #FFFF33;}
+td { padding-left: 5px; }
+tr.odd td { background-color: #FFFFDD; }
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/sharing/query.js	Fri Apr 29 13:34:41 2011 +0100
@@ -0,0 +1,365 @@
+/* query.js */
+var dashboard = {
+  on_load: function ()
+  {
+    this.query = document.getElementById("query");
+    this.param = document.getElementById("param");
+    this.param_caption = document.getElementById("param_caption");
+    this.backward = document.getElementById("backward");
+    this.forward = document.getElementById("forward");
+    this.execute = document.getElementById("execute");
+    this.site_info = document.getElementById("site_info");
+    this.table = document.getElementById("table");
+    this.undo = [];
+    this.redo = 0;
+
+    this.query.addEventListener("change", function(e)
+    {
+      dashboard.set_query(e);
+    }, false);
+
+    this.query.addEventListener("keydown", function (e)
+    {
+      var key = e ? e.which : window.event.keyCode;
+
+      if (key == 13)
+        dashboard.do_query();
+    }, false);
+
+    this.param.addEventListener("change", function(e)
+    {
+      dashboard.set_param(e);
+    }, false);
+
+    this.param.addEventListener("keydown", function (e)
+    {
+      var key = e ? e.which : window.event.keyCode;
+
+      if (key == 13)
+        dashboard.do_query(false);
+    }, false);
+
+    this.backward.addEventListener("click", function(e)
+    {
+      dashboard.go_backward(e);
+    }, false);
+
+    this.forward.addEventListener("click", function(e)
+    {
+      dashboard.go_forward(e);
+    }, false);
+
+    this.execute.addEventListener("click", function(e)
+    {
+      dashboard.do_query(false);
+    }, false);
+
+    this.site_info.addEventListener("click", function(e)
+    {
+      dashboard.get_site_info(false);
+    }, false);
+
+    this.table.addEventListener("click", function(e)
+    {
+      dashboard.table_click(e);
+    }, false);
+  },
+
+  on_unload: function ()
+  {
+  },
+
+  get_caption: function ()
+  {
+    var caption = null;
+
+    switch (this.query.value)
+    {
+      case "9":
+      case "10":
+      case "11":
+      case "13":
+      case "99":
+        caption = "2. Website domain";
+        break;
+
+      default:
+        caption = null;
+    }
+
+    if (caption)
+    {
+      this.param_caption.innerHTML = caption;
+      this.param.disabled = false;
+      this.param.className = "";
+      this.param_caption.className = "";
+      this.param.focus();
+    }
+    else
+    {
+      this.param_caption.innerHTML = "2. Query parameter";
+      this.param.disabled = true;
+      this.param.className = "inactive";
+      this.param_caption.className = "inactive";
+    }
+
+    if (this.param.value && this.param.value != "")
+      this.site_info.disabled = false;
+    else
+      this.site_info.disabled = true;
+
+    return caption;
+  },
+
+  set_query: function (e)
+  {
+    if (!this.get_caption())
+      this.do_query();
+  },
+
+  set_param: function (e)
+  {
+  },
+
+  table_click: function (e)
+  {
+    if (e.target.nodeName.toLowerCase() == "td")
+    {
+      var text = e.target.innerHTML;
+
+      if (text)
+      {
+        this.param.value = text;
+        this.site_info.disabled = false;
+        this.site_info.className = "";
+      }
+    }
+  },
+
+  go_backward: function (e)
+  {
+    if (this.undo.length - this.redo > 0)
+    {
+      this.forward.disabled = false;
+      ++this.redo;
+
+      var state = null;
+
+      if (this.undo.length - this.redo > 0)
+        state = this.undo[this.undo.length - this.redo - 1];
+
+      this.sync_state(state);
+
+      if (this.undo.length - this.redo <= 0)
+        this.backward.disabled = true;
+    }
+  },
+
+  go_forward: function (e)
+  {
+    if (this.redo > 0)
+    {
+      this.backward.disabled = false;
+
+      state = this.undo[this.undo.length - this.redo];
+      this.sync_state(state);
+
+      if (--this.redo == 0)
+        this.forward.disabled = true;
+    }
+  },
+
+  sync_state: function (state)
+  {
+    if (state == null)
+    {
+      this.clear_table();
+      this.query.value = "0";
+      this.param.value = "";
+      this.get_caption();
+    }
+    else
+    {
+      this.query.value = state.query;
+      this.param.value = state.param;
+      this.get_caption();
+      this.do_query(true);
+    }
+  },
+
+  push_undo: function ()
+  {
+    if (this.redo)
+    {
+      this.undo.splice(this.undo.length - this.redo);
+      this.redo = 0;
+      this.forward.disabled = true;
+    }
+
+    this.backward.disabled = false;
+    this.undo.push({"query":this.query.value,"param":this.param.value});
+  },
+
+  do_query: function (redo)
+  {
+    if (this.query.value == 99)
+      return this.get_site_info(redo);
+
+    if (!redo)
+      this.push_undo();
+
+    if (!this.param.disabled && this.param.value == "")
+      alert("please provide value for search parameter");
+    else
+    {
+      var req = new XMLHttpRequest();
+      req.open("POST", "query.php?query="+this.query.value+
+                       "&param="+this.param.value, true);
+      req.onreadystatechange = function (evt) 
+      {
+        if (req.readyState == 4)
+        {
+          if (req.status == 200)
+            dashboard.display_results(req);
+        }
+      };
+
+      req.send(null);
+    }
+  },
+
+  // data is returned as sequence of records terminated by \n
+  // values separated by \t, and first record as column names
+  display_results: function (req)
+  {
+    var table = document.getElementById("table");
+    var data = req.responseText;
+    
+    var records = data.split("\n");
+    var i, j, record, thead, tbody, row, cell;
+
+    // clear table's content
+    this.clear_table();
+
+    // first deal with column names
+    thead = document.createElement("thead");
+    row = document.createElement("tr");
+    thead.appendChild(row);
+    record = records[0].split("\t");
+
+    for (i = 0; i < record.length; ++i)
+    {
+      cell = document.createElement("th");
+      cell.appendChild(document.createTextNode(record[i]));
+      row.appendChild(cell);
+    }
+
+    table.appendChild(thead);
+
+    // next deal with record data if any
+    tbody = document.createElement("tbody");
+
+    for (i = 1; i < records.length; ++i)
+    {
+      record = records[i].split("\t");
+
+      // skip record with missing first column
+      if (record[0] == "")
+        continue;
+
+      row = document.createElement("tr");
+
+      if (i%2)
+        row.className = "odd";
+
+      tbody.appendChild(row);
+
+      for (j = 0; j < record.length; ++j)
+      {
+        cell = document.createElement("td");
+        cell.appendChild(document.createTextNode(record[j]));
+        row.appendChild(cell);
+      }
+    }
+
+    table.appendChild(tbody);
+  },
+
+  get_site_info: function (redo)
+  {
+    this.query.value = "99";
+    this.get_caption();
+
+    if (!redo)
+      this.push_undo();
+
+    if (this.param.value == "")
+      alert("please enter host, e.g. www.facebook.com");
+    else
+    {
+      var req = new XMLHttpRequest();
+      req.open("POST", "site.php?host="+this.param.value, true);
+      req.onreadystatechange = function (evt) 
+      {
+        if (req.readyState == 4)
+        {
+          if (req.status == 200)
+            dashboard.display_site_info(req);
+        }
+      };
+
+      req.send(null);
+    }
+  },
+
+  // data is returned as sequence of records terminated by \n
+  // values separated by \t, and first record as column names
+  display_site_info: function (req)
+  {
+    var table = document.getElementById("table");
+    var data = req.responseText;
+    
+    var records = data.split("\n");
+    var i, j, record, thead, tbody, row, cell;
+
+    this.clear_table();
+
+    // next deal with record data if any
+    tbody = document.createElement("tbody");
+
+    for (i = 1; i < records.length; ++i)
+    {
+      record = records[i].split("\t");
+
+      // skip record with missing first column
+      if (record[0] == "")
+        continue;
+
+      row = document.createElement("tr");
+
+      if (i%2)
+        row.className = "odd";
+
+      tbody.appendChild(row);
+
+      for (j = 0; j < record.length; ++j)
+      {
+        cell = document.createElement("td");
+        cell.appendChild(document.createTextNode(record[j]));
+        row.appendChild(cell);
+      }
+    }
+
+    table.appendChild(tbody);
+  },
+
+  clear_table: function ()
+  {
+    var table = document.getElementById("table");
+    while (table.firstChild)
+      table.removeChild(table.firstChild);
+  }
+};
+
+window.addEventListener("load", function() { dashboard.on_load(); }, false); 
+window.addEventListener("unload", function() { dashboard.on_unload(); }, false); 
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/sharing/query.php	Fri Apr 29 13:34:41 2011 +0100
@@ -0,0 +1,180 @@
+<?php
+
+  $nl = "\n";
+  $tab = "\t";
+  $headers = apache_request_headers();
+
+  function print_record($data)
+  {
+    $nl = "\n";
+    $tab = "\t";
+    $len = sizeof($data);
+
+    for ($i = 0; $i < $len; ++$i)
+    {
+      if ($i > 0)
+        echo $tab;
+
+      echo $data[$i];
+    }
+    echo $nl;
+  }
+
+  function do_query($sql, $names)
+  {
+    $result= mysql_query($sql);
+
+    print_record($names);
+
+    if ($result)
+    {
+      while ($row = mysql_fetch_row($result))
+      {
+        print_record($row);
+      }
+    }
+  }
+
+  // escape string as SQL param
+  function escape1($param)
+  {
+    return mysql_real_escape_string($param);
+  }
+
+  function execute_query($id, $param)
+  {
+    $sql = "unknown as yet";
+    $names = array();
+
+    switch ($id)
+    {
+      case "0":
+        $sql = "SELECT DISTINCT host FROM site_info WHERE lasting_cookies <> 0";
+        $names = array("host");
+        break;
+
+      case "1":
+        $sql = "SELECT DISTINCT host FROM site_info WHERE session_cookies <> 0";
+        $names = array("host");
+        break;
+
+      case "2":
+        $sql = "SELECT host,flash_cookies,int_3rd_party_flash_cookies," .
+        "ext_3rd_party_flash_cookies FROM site_info WHERE flash_cookies <> 0" .
+        " OR int_3rd_party_flash_cookies <> 0 OR ext_3rd_party_flash_cookies <> 0";
+        $names = array("host","direct","internal","external");
+        break;
+
+      case "3":
+        $sql = "SELECT DISTINCT host FROM site_info WHERE dom_storage <> 0";
+        $names = array("host");
+        break;
+
+      case "4":
+        $sql = "SELECT host FROM site_info WHERE invisible_images <> 0";
+        $names = array("host");
+        break;
+
+      case "5":
+        $sql = "SELECT host FROM site_info WHERE html5_pings <> 0";
+        $names = array("host");
+        break;
+
+      case "6":
+        $sql = "SELECT host FROM site_info WHERE p3p <> 0";
+        $names = array("host");
+        break;
+
+      case "7":
+        $sql = "SELECT DISTINCT third_party FROM parties WHERE offsite <> 0";
+        $names = array("3rd party");
+        break;
+
+      case "8":
+        $sql = "SELECT DISTINCT page_host FROM parties WHERE offsite <> 0 " .
+                   "AND third_party LIKE '%" . escape1($param) . "'";
+        $names = array("host");
+        break;
+
+      case "9":
+        $sql = "SELECT DISTINCT third_party FROM parties WHERE offsite = 1 " .
+                   "AND page_host LIKE '%" . escape1($param) . "'";
+        $names = array("3rd party");
+        break;
+
+      case "10":
+        $sql = "SELECT DISTINCT third_party FROM parties WHERE offsite = 2 " .
+                   "AND page_host LIKE '%" . escape1($param) . "'";
+        $names = array("3rd party");
+        break;
+
+      case "11":
+        $sql = "SELECT host,session_cookies,lasting_cookies,flash_cookies," .
+        "int_3rd_party_session_cookies,int_3rd_party_lasting_cookies," .
+        "int_3rd_party_flash_cookies,ext_3rd_party_session_cookies," .
+        "ext_3rd_party_lasting_cookies,ext_3rd_party_flash_cookies" .
+        " FROM site_info WHERE host LIKE '%" . escape1($param) . "'";
+        $names = array("host","session","lasting","flash",
+                       "int session", "int lasting", "int flash",
+                       "ext session", "ext lasting", "ext flash");
+        break;
+
+      case "12":
+        $sql = "SELECT host FROM site_info WHERE geo_permission <> 0";
+        $names = array("host");
+        break;
+
+      default:
+        break;
+    }
+
+    do_query($sql, $names);
+  }
+
+  header('Content-Type: text/plain');
+
+  // read credentials from local file
+  $creds = file_get_contents("credentials");
+
+  if (!$creds)
+  {
+    header("HTTP/1.0 500 Internal Error");
+    die("500 Internal Error - Couldn't get credentials for database access");
+  }
+
+  // file content:  userid:password
+  $creds = explode(":", $creds);
+  $username = trim($creds[0]);
+  $password = trim($creds[1]);
+
+  $database = "privacy-dashboard";
+  $db = mysql_connect("localhost",$username,$password);
+
+  if (!$db)
+  {
+    header("HTTP/1.0 500 Internal Error");
+    die("500 Internal Error - Couldn't open connection to MYSQL: ".mysql_error());
+  }
+
+  if (!mysql_select_db($database))
+  {
+    header("HTTP/1.0 500 Internal Error");
+    die( "500 Internal Error - Unable to select database");
+  }
+
+  // get query from param
+  $query_id = "0";
+  $query_param = "";
+
+  if (array_key_exists("query", $_GET))
+    $query_id = $_GET["query"];
+
+  if (array_key_exists("param", $_GET))
+    $query_param = $_GET["param"];
+
+  execute_query($query_id, $query_param);
+ 
+  mysql_close($db);
+?>
+
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/sharing/share.php	Fri Apr 29 13:34:41 2011 +0100
@@ -0,0 +1,285 @@
+<?php
+  mb_internal_encoding("UTF-8");
+
+  // crude check on data integrity
+  // in conjunction with header
+  function adler32 ($str)
+  {
+    $a = 1;
+    $b = 0;
+    $len = mb_strlen($str);
+
+    for ($i = 0; $i < $len; $i++)
+    {
+      $a = ($a + ord(mb_substr($str, $i, 1))) % 65521; 
+      $b = ($b + $a) % 65521;
+    }
+
+    return $a + $b * 65536;
+  }
+
+  function known_table($table)
+  {
+    return ($table == "relations" || $table == "parties" || $table == "site_intfo");
+  }
+
+  function validate_fields($record, $pattern)
+  {
+    $fields = explode(",", $record);
+    $len = sizeof($fields);
+
+    if ($len != strlen($pattern)
+      return false;
+
+    // regular expression for matching a domain name
+    $reg = "/^[a-z0-9][a-z0-9\-]+[a-z0-9](\.[a-z]{2,4})+$/i";
+
+    for ($i = 0; $i < $len; ++$i)
+    {
+      if ($pattern[$i] == ord('a'))
+      {
+        if (!preg_match($reg, trim($fields[i])))
+          return false;
+      }
+      else if ($pattern[$i] == ord('i'))
+      {
+        try
+        {
+          $n = (int)($fields[i]);
+
+          if ($n < 0)
+            return false;
+        }
+        catch (Exception $e)
+        {
+          return false;
+        }
+      }
+      else
+        return false;
+    }
+
+    return true;
+  }
+
+  function update_relations($data)
+  {
+    $len = count($data) - 1;  // allowing for terminating \n
+
+    for ($i = 0; $i < $len; $i++)
+    {
+      $record = $data[$i];
+
+      if (!validate_fields($record, "aai"))
+      {
+        header("HTTP/1.0 400 Bad Request");
+        die("400 Bad Request - malformed record");
+      }
+
+      $query = "REPLACE relations VALUES (".$record.")";
+
+      if (!mysql_query($query))
+      {
+        header("HTTP/1.0 400 Bad Request");
+        die("400 Bad Request - ".mysql_error());
+      }
+    }
+  }
+
+  function update_parties($data)
+  {
+    $len = count($data) - 1;  // allowing for terminating \n
+
+    for ($i = 0; $i < $len; $i++)
+    {
+      $record = $data[$i];
+
+      if (!validate_fields($record, "aai"))
+      {
+        header("HTTP/1.0 400 Bad Request");
+        die("400 Bad Request - malformed record");
+      }
+
+      $query = "REPLACE parties VALUES (".$record.")";
+
+      if (!mysql_query($query))
+      {
+        header("HTTP/1.0 400 Bad Request");
+        die("400 Bad Request - ".mysql_error());
+      }
+    }
+  }
+
+  function max_value($a, $b)
+  {
+    $x = (int)$a;
+    $y = (int)$b;
+    return ($x > $y ? $a : $b);
+  }
+
+  // used to keep count of page loads per site
+  function sum_values($a, $b)
+  {
+    $x = (int)$a;
+    $y = (int)$b;
+    return ("" + ($x + $y));
+  }
+
+  function update_site_info_record($record)
+  {
+    if (!validate_fields($record, "aiiiiiiiiiiiiiiiiii"))
+    {
+      header("HTTP/1.0 400 Bad Request");
+      die("400 Bad Request - malformed record");
+    }
+
+    // extract host name from first field
+    $fields = explode(",", $record);
+    $host = $fields[0];
+
+    // use it to retrieve existing record if one exists
+    $query = "SELECT ALL FROM site_info WHERE host=".$host;
+
+    $result = mysql_query($query);
+    $row = mysql_fetch_array($result);
+
+    if ($row)
+    {
+      $visited = sum_values($fields[1], $row["visited"]);
+      $session_cookies = max_value($fields[2], $row["session_cookies"]);
+      $lasting_cookies = max_value($fields[3], $row["lasting_cookies"]);
+      $flash_cookies = max_value($fields[4], $row["lasting_cookies"]);
+      $int_3rd_parties = max_value($fields[5], $row["int_3rd_parties"]);
+      $ext_3rd_parties = max_value($fields[6], $row["ext_3rd_parties"]);
+      $int_3rd_party_session_cookies =
+         max_value($fields[7], $row["int_3rd_party_session_cookies"]);
+      $int_3rd_party_lasting_cookies =
+         max_value($fields[8], $row["int_3rd_party_lasting_cookies"]);
+      $int_3rd_party_flash_cookies =
+         max_value($fields[9], $row["int_3rd_party_flash_cookies"]);
+      $ext_3rd_party_session_cookies =
+         max_value($fields[10], $row["ext_3rd_party_session_cookies"]);
+      $ext_3rd_party_lasting_cookies =
+         max_value($fields[11], $row["ext_3rd_party_lasting_cookies"]);
+      $ext_3rd_party_flash_cookies =
+         max_value($fields[12], $row["ext_3rd_party_flash_cookies"]);
+      $dom_storage = max_value($fields[13], $row["dom_storage"]);
+      $html5_pings = max_value($fields[14], $row["html5_pings"]);
+      $invisible_images = max_value($fields[15], $row["invisible_images"]);
+      $suspicious_urls = max_value($fields[16], $row["suspicious_urls"]);
+      $geo_permission = max_value($fields[17], $row["geo_permission"]);
+      $p3p = max_value($fields[18], $row["p3p"]);
+
+      $record = implode(",", Array($host, $session_cookies, $lasting_cookies,
+        $int_3rd_parties,$ext_3rd_parties, $int_3rd_party_session_cookies,
+        $int_3rd_party_lasting_cookies, $int_3rd_party_flash_cookies,
+        $ext_3rd_party_session_cookies, $ext_3rd_party_lasting_cookies,
+        $ext_3rd_party_flash_cookies, $dom_storage, $html5_pings,
+        $invisible_images, $suspicious_urls, $geo_permission, $p3p));
+
+      $query = "REPLACE site_info VALUES (".$record.")";
+
+      if (!mysql_query($query))
+      {
+        header("HTTP/1.0 400 Bad Request");
+        die("400 Bad Request - ".mysql_error());
+      }
+    }
+    else
+    {
+      $query = "INSERT site_info VALUES (".$record.")";
+
+      if (!mysql_query($query))
+      {
+        header("HTTP/1.0 400 Bad Request");
+        die("400 Bad Request - ".mysql_error());
+      }
+    }
+  }
+
+  function update_site_info($data)
+  {
+    $len = count($data) - 1;  // allowing for terminating \n
+    $expected = 19;
+
+    for ($i = 0; $i < $len; $i++)
+    {
+      $record = $data[$i];
+      $fields = substr_count($record, ",") + 1;
+
+      if ($expected != $fields)
+      {
+        header("HTTP/1.0 400 Bad Request");
+        die("400 Bad Request - malformed record");
+      }
+
+      update_site_info_record($record);
+    }
+  }
+
+  $nl = "\n";
+  $headers = apache_request_headers();
+  $body = file_get_contents('php://input');
+  $checksum = $headers["X-Data-Check"];
+  $table = $headers["Dashboard-Table"];
+
+  $type = $headers["Content-Type"];
+  $mime = explode(';', $type);
+
+  if ($mime[0] != "text/plain" ||
+      !$checksum ||
+      adler32($body) != $checksum ||
+      !known_table($table))
+  {
+    header("HTTP/1.0 400 Bad Request");
+    die("Bad Request");
+  }
+
+  $data = explode("\n", $body);
+
+  // read credentials from local file
+  $creds = file_get_contents("credentials");
+
+  if (!$creds)
+  {
+    header("HTTP/1.0 500 Internal Error");
+    die("500 Internal Error - Couldn't get credentials for database access");
+  }
+
+  // file content:  userid:password
+  $creds = explode(":", $creds);
+  $username = trim($creds[0]);
+  $password = trim($creds[1]);
+
+  $database = "privacy-dashboard";
+  $db = mysql_connect("localhost",$username,$password);
+
+  if (!$db)
+  {
+    header("HTTP/1.0 500 Internal Error");
+    die("500 Internal Error - Couldn't open connection to MYSQL: ".mysql_error());
+  }
+
+  if (!mysql_select_db($database))
+  {
+    header("HTTP/1.0 500 Internal Error");
+    die( "500 Internal Error - Unable to select database");
+  }
+
+  if ($table == "relations")
+    update_relations($data);
+  if ($table == "parties")
+    update_parties($data);
+  else if ($table == "site_info")
+    update_site_info($data);
+  
+  mysql_close($db);
+  
+  header('Content-Type: text/html');
+?>
+<html>
+<title>Thanks for sharing</title>
+<h1>Thanks for sharing</h1>
+<p>Thanks for helping to make the Web a little bit more transparent.</p>
+</html>
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/sharing/site.php	Fri Apr 29 13:34:41 2011 +0100
@@ -0,0 +1,85 @@
+<?php
+
+  $nl = "\n";
+  $tab = "\t";
+  $headers = apache_request_headers();
+
+  function print_record($names, $data)
+  {
+    $nl = "\n";
+    $tab = "\t";
+    $len = sizeof($data);
+    echo "len = " . $len . "; ";
+
+    for ($i = 0; $i < $len; ++$i)
+    {
+      echo $names[$i];
+      echo $tab;
+      echo $data[$i];
+      echo $nl;
+    }
+  }
+
+  function do_query($sql, $names)
+  {
+    $result= mysql_query($sql);
+
+    if ($result)
+    {
+      $row = mysql_fetch_row($result);
+      print_record($names, $row);
+    }
+  }
+
+  // escape string as SQL param
+  function escape1($param)
+  {
+    return $param;
+  }
+
+  function site_info($host)
+  {
+    $sql = "SELECT * FROM site_info WHERE host = '" . escape1($host) . "'";
+    $names = array("host","reported number of visits","session cookies",
+     "lasting cookies","flash cookies",
+     "internal 3rd party content","external 3rd party content",
+     "internal 3rd session cookies", "internal 3rd lasting cookies",
+     "internal 3rd flash coolkies","external 3rd session cookies",
+     "external 3rd lasting cookies","external 3rd flash cookies",
+     "use of DOM storage","html5 ping attributes","invisible images",
+     "suspicious urls","permission to access geolocation","p3p policy");
+    do_query($sql, $names);
+  }
+
+  $username = "www-data";
+  $password = "nutmeg23";  // oops security hole!!!!
+  $database = "privacy-dashboard";
+
+  $db = mysql_connect("localhost",$username,$password);
+
+  if (!$db)
+  {
+    header("HTTP/1.0 500 Internal Error");
+    die("500 Internal Error - Couldn't open connection to MYSQL: ".$mysql_error());
+  }
+
+  if (!mysql_select_db($database))
+  {
+    header("HTTP/1.0 500 Internal Error");
+    die( "500 Internal Error - Unable to select database");
+  }
+
+  header('Content-Type: text/plain');
+
+  if (array_key_exists("host", $_GET))
+    site_info($_GET["host"]);
+  else
+  {
+    mysql_close($db);
+    die("no such host");
+  }
+ 
+  mysql_close($db);
+?>
+
+
Binary file sharing/stucco.jpg has changed