tor-browser

The Tor Browser
git clone https://git.dasho.dev/tor-browser.git
Log | Files | Refs | README | LICENSE

referrer_testserver.sjs (18695B)


      1 /*
      2  * Test server for iframe, anchor, and area referrer attributes.
      3  * https://bugzilla.mozilla.org/show_bug.cgi?id=1175736
      4  * Also server for further referrer tests such as redirecting tests
      5  * bug 1174913, bug 1175736, bug 1184781
      6  */
      7 
      8 const SJS = "referrer_testserver.sjs?";
      9 const SJS_PATH = "/tests/dom/security/test/referrer-policy/";
     10 const BASE_ORIGIN = "example.com";
     11 const BASE_URL = BASE_ORIGIN + SJS_PATH + SJS;
     12 const SHARED_KEY = SJS;
     13 const SAME_ORIGIN = "mochi.test:8888" + SJS_PATH + SJS;
     14 const CROSS_ORIGIN_URL = "test1.example.com" + SJS_PATH + SJS;
     15 const HSTS_URL = "includesubdomains.preloaded.test" + SJS_PATH + SJS;
     16 
     17 const IMG_BYTES = atob(
     18   "iVBORw0KGgoAAAANSUhEUgAAAAUAAAAFCAYAAACNbyblAAAAHElEQVQI12" +
     19     "P4//8/w38GIAXDIBKE0DHxgljNBAAO9TXL0Y4OHwAAAABJRU5ErkJggg=="
     20 );
     21 
     22 function createTestUrl(
     23   aPolicy,
     24   aAction,
     25   aName,
     26   aType,
     27   aSchemeFrom,
     28   aSchemeTo,
     29   crossOrigin,
     30   referrerPolicyHeader
     31 ) {
     32   var schemeTo = aSchemeTo || "http";
     33   var schemeFrom = aSchemeFrom || "http";
     34   var rpHeader = referrerPolicyHeader || "";
     35   var url = schemeTo + "://";
     36   url += crossOrigin ? CROSS_ORIGIN_URL : BASE_URL;
     37   url +=
     38     "ACTION=" +
     39     aAction +
     40     "&" +
     41     "policy=" +
     42     aPolicy +
     43     "&" +
     44     "NAME=" +
     45     aName +
     46     "&" +
     47     "type=" +
     48     aType +
     49     "&" +
     50     "RP_HEADER=" +
     51     rpHeader +
     52     "&" +
     53     "SCHEME_FROM=" +
     54     schemeFrom;
     55   return url;
     56 }
     57 
     58 // test page using iframe referrer attribute
     59 // if aParams are set this creates a test where the iframe url is a redirect
     60 function createIframeTestPageUsingRefferer(
     61   aMetaPolicy,
     62   aAttributePolicy,
     63   aNewAttributePolicy,
     64   aName,
     65   aParams,
     66   aSchemeFrom,
     67   aSchemeTo,
     68   aChangingMethod
     69 ) {
     70   var metaString = "";
     71   if (aMetaPolicy) {
     72     metaString = `<meta name="referrer" content="${aMetaPolicy}">`;
     73   }
     74   var changeString = "";
     75   if (aChangingMethod === "setAttribute") {
     76     changeString = `document.getElementById("myframe").setAttribute("referrerpolicy", "${aNewAttributePolicy}")`;
     77   } else if (aChangingMethod === "property") {
     78     changeString = `document.getElementById("myframe").referrerPolicy = "${aNewAttributePolicy}"`;
     79   }
     80   var iFrameString = `<iframe src="" id="myframe" ${
     81     aAttributePolicy ? ` referrerpolicy="${aAttributePolicy}"` : ""
     82   }>iframe</iframe>`;
     83   var iframeUrl = "";
     84   if (aParams) {
     85     aParams.delete("ACTION");
     86     aParams.append("ACTION", "redirectIframe");
     87     iframeUrl = "http://" + CROSS_ORIGIN_URL + aParams.toString();
     88   } else {
     89     iframeUrl = createTestUrl(
     90       aAttributePolicy,
     91       "test",
     92       aName,
     93       "iframe",
     94       aSchemeFrom,
     95       aSchemeTo
     96     );
     97   }
     98 
     99   return `<!DOCTYPE HTML>
    100            <html>
    101              <head>
    102              ${metaString}
    103              </head>
    104              <body>
    105                ${iFrameString}
    106                <script>
    107                  window.addEventListener("load", function() {
    108                    ${changeString}
    109                    document.getElementById("myframe").onload = function(){
    110                     parent.postMessage("childLoadComplete", "http://mochi.test:8888");
    111                    };
    112                    document.getElementById("myframe").src = "${iframeUrl}";
    113                  }.bind(window), false);
    114                </script>
    115              </body>
    116            </html>`;
    117 }
    118 
    119 function buildAnchorString(
    120   aMetaPolicy,
    121   aReferrerPolicy,
    122   aName,
    123   aRelString,
    124   aSchemeFrom,
    125   aSchemeTo
    126 ) {
    127   if (aReferrerPolicy) {
    128     return `<a href="${createTestUrl(
    129       aReferrerPolicy,
    130       "test",
    131       aName,
    132       "link",
    133       aSchemeFrom,
    134       aSchemeTo
    135     )}" referrerpolicy="${aReferrerPolicy}" id="link" ${aRelString}>${aReferrerPolicy}</a>`;
    136   }
    137   return `<a href="${createTestUrl(
    138     aMetaPolicy,
    139     "test",
    140     aName,
    141     "link",
    142     aSchemeFrom,
    143     aSchemeTo
    144   )}" id="link" ${aRelString}>link</a>`;
    145 }
    146 
    147 function buildAreaString(
    148   aMetaPolicy,
    149   aReferrerPolicy,
    150   aName,
    151   aRelString,
    152   aSchemeFrom,
    153   aSchemeTo
    154 ) {
    155   var result = `<img src="file_mozfiledataurl_img.jpg" alt="image" usemap="#imageMap">`;
    156   result += `<map name="imageMap">`;
    157   if (aReferrerPolicy) {
    158     result += `<area shape="circle" coords="1,1,1" href="${createTestUrl(
    159       aReferrerPolicy,
    160       "test",
    161       aName,
    162       "link",
    163       aSchemeFrom,
    164       aSchemeTo
    165     )}" alt="theArea" referrerpolicy="${aReferrerPolicy}" id="link" ${aRelString}>`;
    166   } else {
    167     result += `<area shape="circle" coords="1,1,1" href="${createTestUrl(
    168       aMetaPolicy,
    169       "test",
    170       aName,
    171       "link",
    172       aSchemeFrom,
    173       aSchemeTo
    174     )}" alt="theArea" id="link" ${aRelString}>`;
    175   }
    176   result += `</map>`;
    177 
    178   return result;
    179 }
    180 
    181 // test page using anchor or area referrer attribute
    182 function createAETestPageUsingRefferer(
    183   aMetaPolicy,
    184   aAttributePolicy,
    185   aNewAttributePolicy,
    186   aName,
    187   aRel,
    188   aStringBuilder,
    189   aSchemeFrom,
    190   aSchemeTo,
    191   aChangingMethod
    192 ) {
    193   var metaString = "";
    194   if (aMetaPolicy) {
    195     metaString = `<head><meta name="referrer" content="${aMetaPolicy}"></head>`;
    196   }
    197   var changeString = "";
    198   if (aChangingMethod === "setAttribute") {
    199     changeString = `document.getElementById("link").setAttribute("referrerpolicy", "${aNewAttributePolicy}")`;
    200   } else if (aChangingMethod === "property") {
    201     changeString = `document.getElementById("link").referrerPolicy = "${aNewAttributePolicy}"`;
    202   }
    203   var relString = "";
    204   if (aRel) {
    205     relString = `rel="noreferrer"`;
    206   }
    207   var elementString = aStringBuilder(
    208     aMetaPolicy,
    209     aAttributePolicy,
    210     aName,
    211     relString,
    212     aSchemeFrom,
    213     aSchemeTo
    214   );
    215 
    216   return `<!DOCTYPE HTML>
    217            <html>
    218              ${metaString}
    219              <body>
    220                ${elementString}
    221                <script>
    222                  window.addEventListener("load", function() {
    223                    ${changeString}
    224                    document.getElementById("link").click();
    225                  }.bind(window), false);
    226                </script>
    227              </body>
    228            </html>`;
    229 }
    230 
    231 // test page using anchor target=_blank rel=noopener
    232 function createTargetBlankRefferer(
    233   aMetaPolicy,
    234   aName,
    235   aSchemeFrom,
    236   aSchemeTo,
    237   aRpHeader
    238 ) {
    239   var metaString = "";
    240   if (aMetaPolicy) {
    241     metaString = `<head><meta name="referrer" content="${aMetaPolicy}"></head>`;
    242   }
    243   var elementString = `<a href="${createTestUrl(
    244     aMetaPolicy,
    245     "test",
    246     aName,
    247     "link",
    248     aSchemeFrom,
    249     aSchemeTo,
    250     aRpHeader
    251   )}" target=_blank rel="noopener" id="link">link</a>`;
    252 
    253   return `<!DOCTYPE HTML>
    254            <html>
    255              ${metaString}
    256              <body>
    257                ${elementString}
    258                <script>
    259                  window.addEventListener("load", function() {
    260                    let link = document.getElementById("link");
    261                    SpecialPowers.wrap(window).parent.postMessage("childLoadReady", "*");
    262                    link.click();
    263                  }.bind(window), false);
    264                </script>
    265              </body>
    266            </html>`;
    267 }
    268 
    269 // creates test page with img that is a redirect
    270 function createImgTestCase(aParams, aAttributePolicy, aRedirect) {
    271   var metaString = "";
    272   if (aParams.has("META_POLICY")) {
    273     metaString = `<meta name="referrer" content="${aParams.get(
    274       "META_POLICY"
    275     )}">`;
    276   }
    277   aParams.delete("ACTION");
    278   if (aRedirect) {
    279     aParams.append("ACTION", "redirectImg");
    280   } else {
    281     aParams.append("ACTION", "test");
    282     aParams.append("type", "img");
    283   }
    284   var imgUrl =
    285     "http://" +
    286     (aParams.get("HSTS") ? HSTS_URL : CROSS_ORIGIN_URL) +
    287     aParams.toString();
    288 
    289   return `<!DOCTYPE HTML>
    290           <html>
    291           <head>
    292           <meta charset="utf-8">
    293           ${metaString}
    294           <title>Test referrer policies on redirect (img)</title>
    295           </head>
    296           <body>
    297           <img id="testImg" src="${imgUrl}" ${
    298             aAttributePolicy ? ` referrerpolicy="${aAttributePolicy}"` : ""
    299           }>
    300           <script>
    301             window.addEventListener("load", function() {
    302               parent.postMessage("childLoadComplete", "http://mochi.test:8888");
    303             }.bind(window), false);
    304           </script>
    305           </body>
    306           </html>`;
    307 }
    308 
    309 // test page using link referrer attribute
    310 function createLinkPageUsingRefferer(
    311   aMetaPolicy,
    312   aAttributePolicy,
    313   aNewAttributePolicy,
    314   aName,
    315   aRel,
    316   aStringBuilder,
    317   aSchemeFrom,
    318   aSchemeTo,
    319   aTestType
    320 ) {
    321   var metaString = "";
    322   if (aMetaPolicy) {
    323     metaString = `<meta name="referrer" content="${aMetaPolicy}">`;
    324   }
    325 
    326   var changeString = "";
    327   var policy = aAttributePolicy ? aAttributePolicy : aMetaPolicy;
    328   var elementString = aStringBuilder(
    329     policy,
    330     aName,
    331     aRel,
    332     aSchemeFrom,
    333     aSchemeTo,
    334     aTestType
    335   );
    336 
    337   if (aTestType === "setAttribute") {
    338     changeString = `var link = document.getElementById("test_link");
    339                     link.setAttribute("referrerpolicy", "${aNewAttributePolicy}");
    340                     link.href = "${createTestUrl(
    341                       policy,
    342                       "test",
    343                       aName,
    344                       "link_element_" + aRel,
    345                       aSchemeFrom,
    346                       aSchemeTo
    347                     )}";`;
    348   } else if (aTestType === "property") {
    349     changeString = `var link = document.getElementById("test_link");
    350                     link.referrerPolicy = "${aNewAttributePolicy}";
    351                     link.href = "${createTestUrl(
    352                       policy,
    353                       "test",
    354                       aName,
    355                       "link_element_" + aRel,
    356                       aSchemeFrom,
    357                       aSchemeTo
    358                     )}";`;
    359   }
    360 
    361   return `<!DOCTYPE HTML>
    362            <html>
    363              <head>
    364                ${metaString}
    365              </head>
    366              <body>
    367                 ${elementString}
    368                 <script>
    369                   ${changeString}
    370                 </script>
    371              </body>
    372            </html>`;
    373 }
    374 
    375 function createFetchUserControlRPTestCase(
    376   aName,
    377   aSchemeFrom,
    378   aSchemeTo,
    379   crossOrigin
    380 ) {
    381   var srcUrl = createTestUrl(
    382     "",
    383     "test",
    384     aName,
    385     "fetch",
    386     aSchemeFrom,
    387     aSchemeTo,
    388     crossOrigin
    389   );
    390 
    391   return `<!DOCTYPE HTML>
    392           <html>
    393           <head>
    394           <meta charset="utf-8">
    395           <title>Test user control referrer policies</title>
    396           </head>
    397           <body>
    398           <script>
    399             fetch("${srcUrl}", {referrerPolicy: ""}).then(function (response) {
    400               window.parent.postMessage("childLoadComplete", "http://mochi.test:8888");
    401             });
    402           </script>
    403           </body>
    404           </html>`;
    405 }
    406 
    407 function buildLinkString(
    408   aPolicy,
    409   aName,
    410   aRel,
    411   aSchemeFrom,
    412   aSchemeTo,
    413   aTestType
    414 ) {
    415   var href = "";
    416   var onChildComplete = `window.parent.postMessage("childLoadComplete", "http://mochi.test:8888");`;
    417   var policy = "";
    418   var asString = "";
    419   var relString = "";
    420 
    421   if (aRel) {
    422     relString = `rel="${aRel}"`;
    423   }
    424 
    425   if (aPolicy) {
    426     policy = `referrerpolicy=${aPolicy}`;
    427   }
    428 
    429   if (aRel == "preload") {
    430     asString = 'as="image"';
    431   }
    432 
    433   if (!aTestType) {
    434     href = `href=${createTestUrl(
    435       aPolicy,
    436       "test",
    437       aName,
    438       "link_element_" + aRel,
    439       aSchemeFrom,
    440       aSchemeTo
    441     )}`;
    442   }
    443 
    444   return `<link ${relString} ${href} ${policy} ${asString} id="test_link" onload='${onChildComplete}' onerror='${onChildComplete}'>`;
    445 }
    446 // eslint-disable-next-line complexity
    447 function handleRequest(request, response) {
    448   var params = new URLSearchParams(request.queryString);
    449   var action = params.get("ACTION");
    450   var schemeFrom = params.get("SCHEME_FROM") || "http";
    451   var schemeTo = params.get("SCHEME_TO") || "http";
    452   var crossOrigin = params.get("CROSS_ORIGIN") || false;
    453   var referrerPolicyHeader = params.get("RP_HEADER") || "";
    454 
    455   response.setHeader("Access-Control-Allow-Origin", "*", false);
    456   if (referrerPolicyHeader) {
    457     response.setHeader("Referrer-Policy", referrerPolicyHeader, false);
    458   }
    459 
    460   if (action === "resetState") {
    461     setSharedState(SHARED_KEY, "{}");
    462     response.write("");
    463     return;
    464   }
    465   if (action === "get-test-results") {
    466     // ?action=get-result
    467     response.setHeader("Cache-Control", "no-cache", false);
    468     response.setHeader("Content-Type", "text/plain", false);
    469     response.write(getSharedState(SHARED_KEY));
    470     return;
    471   }
    472   if (action === "redirect") {
    473     response.write(
    474       '<script>parent.postMessage("childLoadComplete", "http://mochi.test:8888");</script>'
    475     );
    476     return;
    477   }
    478   if (action === "redirectImg") {
    479     params.delete("ACTION");
    480     params.append("ACTION", "test");
    481     params.append("type", "img");
    482     // 302 found, 301 Moved Permanently, 303 See Other, 307 Temporary Redirect
    483     response.setStatusLine("1.1", 302, "found");
    484     response.setHeader(
    485       "Location",
    486       "http://" + CROSS_ORIGIN_URL + params.toString(),
    487       false
    488     );
    489     return;
    490   }
    491   if (action === "redirectIframe") {
    492     params.delete("ACTION");
    493     params.append("ACTION", "test");
    494     params.append("type", "iframe");
    495     // 302 found, 301 Moved Permanently, 303 See Other, 307 Temporary Redirect
    496     response.setStatusLine("1.1", 302, "found");
    497     response.setHeader(
    498       "Location",
    499       "http://" + CROSS_ORIGIN_URL + params.toString(),
    500       false
    501     );
    502     return;
    503   }
    504   if (action === "test") {
    505     // ?action=test&policy=origin&name=name
    506     let policy = params.get("policy");
    507     let name = params.get("NAME");
    508     let type = params.get("type");
    509     let result = getSharedState(SHARED_KEY);
    510 
    511     result = result ? JSON.parse(result) : {};
    512 
    513     var referrerLevel = "none";
    514     var test = {};
    515     if (request.hasHeader("Referer")) {
    516       var referrer = request.getHeader("Referer");
    517       if (referrer.indexOf("referrer_testserver") > 0) {
    518         referrerLevel = "full";
    519       } else if (referrer.indexOf(schemeFrom + "://example.com") == 0) {
    520         referrerLevel = "origin";
    521       } else {
    522         // this is never supposed to happen
    523         referrerLevel = "other-origin";
    524       }
    525       test.referrer = referrer;
    526     } else {
    527       test.referrer = "";
    528     }
    529     test.policy = referrerLevel;
    530     test.expected = policy;
    531 
    532     result[name] = test;
    533 
    534     setSharedState(SHARED_KEY, JSON.stringify(result));
    535 
    536     if (type === "img" || type == "link_element_preload") {
    537       // return image
    538       response.setHeader("Content-Type", "image/png");
    539       response.write(IMG_BYTES);
    540       return;
    541     }
    542     if (type === "iframe") {
    543       // return iframe page
    544       response.write("<html><body>I am the iframe</body></html>");
    545       return;
    546     }
    547     if (type === "link") {
    548       // forward link click to redirect URL to finish test
    549       var loc = "http://" + BASE_URL + "ACTION=redirect";
    550       response.setStatusLine("1.1", 302, "Found");
    551       response.setHeader("Location", loc, false);
    552     }
    553     return;
    554   }
    555 
    556   response.setHeader("Cache-Control", "no-cache", false);
    557   response.setHeader("Content-Type", "text/html; charset=utf-8", false);
    558 
    559   // parse test arguments and start test
    560   var attributePolicy = params.get("ATTRIBUTE_POLICY") || "";
    561   var newAttributePolicy = params.get("NEW_ATTRIBUTE_POLICY") || "";
    562   var metaPolicy = params.get("META_POLICY") || "";
    563   var rel = params.get("REL") || "";
    564   var name = params.get("NAME");
    565 
    566   // anchor & area
    567   var _getPage = createAETestPageUsingRefferer.bind(
    568     null,
    569     metaPolicy,
    570     attributePolicy,
    571     newAttributePolicy,
    572     name,
    573     rel
    574   );
    575   var _getAnchorPage = _getPage.bind(
    576     null,
    577     buildAnchorString,
    578     schemeFrom,
    579     schemeTo
    580   );
    581   var _getAreaPage = _getPage.bind(null, buildAreaString, schemeFrom, schemeTo);
    582 
    583   // aMetaPolicy, aAttributePolicy, aNewAttributePolicy, aName, aChangingMethod, aStringBuilder
    584   if (action === "generate-anchor-policy-test") {
    585     response.write(_getAnchorPage());
    586     return;
    587   }
    588   if (action === "generate-anchor-changing-policy-test-set-attribute") {
    589     response.write(_getAnchorPage("setAttribute"));
    590     return;
    591   }
    592   if (action === "generate-anchor-changing-policy-test-property") {
    593     response.write(_getAnchorPage("property"));
    594     return;
    595   }
    596   if (action === "generate-area-policy-test") {
    597     response.write(_getAreaPage());
    598     return;
    599   }
    600   if (action === "generate-area-changing-policy-test-set-attribute") {
    601     response.write(_getAreaPage("setAttribute"));
    602     return;
    603   }
    604   if (action === "generate-area-changing-policy-test-property") {
    605     response.write(_getAreaPage("property"));
    606     return;
    607   }
    608   if (action === "generate-anchor-target-blank-policy-test") {
    609     response.write(
    610       createTargetBlankRefferer(
    611         metaPolicy,
    612         name,
    613         schemeFrom,
    614         schemeTo,
    615         referrerPolicyHeader
    616       )
    617     );
    618     return;
    619   }
    620 
    621   // iframe
    622   _getPage = createIframeTestPageUsingRefferer.bind(
    623     null,
    624     metaPolicy,
    625     attributePolicy,
    626     newAttributePolicy,
    627     name,
    628     "",
    629     schemeFrom,
    630     schemeTo
    631   );
    632 
    633   // aMetaPolicy, aAttributePolicy, aNewAttributePolicy, aName, aChangingMethod
    634   if (action === "generate-iframe-policy-test") {
    635     response.write(_getPage());
    636     return;
    637   }
    638   if (action === "generate-iframe-changing-policy-test-set-attribute") {
    639     response.write(_getPage("setAttribute"));
    640     return;
    641   }
    642   if (action === "generate-iframe-changing-policy-test-property") {
    643     response.write(_getPage("property"));
    644     return;
    645   }
    646 
    647   // redirect tests with img and iframe
    648   if (action === "generate-img-redirect-policy-test") {
    649     response.write(createImgTestCase(params, attributePolicy, true));
    650     return;
    651   }
    652   if (action === "generate-iframe-redirect-policy-test") {
    653     response.write(
    654       createIframeTestPageUsingRefferer(
    655         metaPolicy,
    656         attributePolicy,
    657         newAttributePolicy,
    658         name,
    659         params,
    660         schemeFrom,
    661         schemeTo
    662       )
    663     );
    664     return;
    665   }
    666 
    667   if (action === "generate-img-policy-test") {
    668     response.write(createImgTestCase(params, attributePolicy, false));
    669     return;
    670   }
    671 
    672   _getPage = createLinkPageUsingRefferer.bind(
    673     null,
    674     metaPolicy,
    675     attributePolicy,
    676     newAttributePolicy,
    677     name,
    678     rel
    679   );
    680   var _getLinkPage = _getPage.bind(null, buildLinkString, schemeFrom, schemeTo);
    681 
    682   // link
    683   if (action === "generate-link-policy-test") {
    684     response.write(_getLinkPage());
    685     return;
    686   }
    687   if (action === "generate-link-policy-test-set-attribute") {
    688     response.write(_getLinkPage("setAttribute"));
    689     return;
    690   }
    691   if (action === "generate-link-policy-test-property") {
    692     response.write(_getLinkPage("property"));
    693     return;
    694   }
    695 
    696   if (action === "generate-fetch-user-control-policy-test") {
    697     response.write(
    698       createFetchUserControlRPTestCase(name, schemeFrom, schemeTo, crossOrigin)
    699     );
    700     return;
    701   }
    702 
    703   response.write("I don't know action " + action);
    704 }