tor-browser

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

aboutPolicies.js (12610B)


      1 /* This Source Code Form is subject to the terms of the Mozilla Public
      2 * License, v. 2.0. If a copy of the MPL was not distributed with this
      3 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
      4 
      5 "use strict";
      6 
      7 const { XPCOMUtils } = ChromeUtils.importESModule(
      8  "resource://gre/modules/XPCOMUtils.sys.mjs"
      9 );
     10 
     11 ChromeUtils.defineESModuleGetters(this, {
     12  schema: "resource:///modules/policies/schema.sys.mjs",
     13 });
     14 
     15 function col(text, className) {
     16  let column = document.createElement("td");
     17  if (className) {
     18    column.classList.add(className);
     19  }
     20  let content = document.createTextNode(text);
     21  column.appendChild(content);
     22  return column;
     23 }
     24 
     25 function link(text) {
     26  let column = document.createElement("td");
     27  let a = document.createElement("a");
     28  a.href = "https://mozilla.github.io/policy-templates/#" + text.toLowerCase();
     29  a.target = "_blank";
     30  let content = document.createTextNode(text);
     31  a.appendChild(content);
     32  column.appendChild(a);
     33  return column;
     34 }
     35 
     36 function addMissingColumns() {
     37  const table = document.getElementById("activeContent");
     38  let maxColumns = 0;
     39 
     40  // count the number of columns per row and set the max number of columns
     41  for (let i = 0, length = table.rows.length; i < length; i++) {
     42    if (maxColumns < table.rows[i].cells.length) {
     43      maxColumns = table.rows[i].cells.length;
     44    }
     45  }
     46 
     47  // add the missing columns
     48  for (let i = 0, length = table.rows.length; i < length; i++) {
     49    const rowLength = table.rows[i].cells.length;
     50 
     51    if (rowLength < maxColumns) {
     52      let missingColumns = maxColumns - rowLength;
     53 
     54      while (missingColumns > 0) {
     55        table.rows[i].insertCell();
     56        missingColumns--;
     57      }
     58    }
     59  }
     60 }
     61 
     62 /*
     63 * This function generates the Active Policies content to be displayed by calling
     64 * a recursive function called generatePolicy() according to the policy schema.
     65 */
     66 
     67 function generateActivePolicies(data) {
     68  let new_cont = document.getElementById("activeContent");
     69  new_cont.classList.add("active-policies");
     70 
     71  let policy_count = 0;
     72 
     73  for (let policyName in data) {
     74    const color_class = ++policy_count % 2 === 0 ? "even" : "odd";
     75 
     76    if (schema.properties[policyName].type == "array") {
     77      for (let count in data[policyName]) {
     78        let isFirstRow = count == 0;
     79        let isLastRow = count == data[policyName].length - 1;
     80        let row = document.createElement("tr");
     81        row.classList.add(color_class);
     82        row.appendChild(col(isFirstRow ? policyName : ""));
     83        generatePolicy(
     84          data[policyName][count],
     85          row,
     86          1,
     87          new_cont,
     88          isLastRow,
     89          data[policyName].length > 1
     90        );
     91      }
     92    } else if (schema.properties[policyName].type == "object") {
     93      let count = 0;
     94      for (let obj in data[policyName]) {
     95        let isFirstRow = count == 0;
     96        let isLastRow = count == Object.keys(data[policyName]).length - 1;
     97        let row = document.createElement("tr");
     98        row.classList.add(color_class);
     99        row.appendChild(col(isFirstRow ? policyName : ""));
    100        row.appendChild(col(obj));
    101        generatePolicy(
    102          data[policyName][obj],
    103          row,
    104          2,
    105          new_cont,
    106          isLastRow,
    107          true
    108        );
    109        count++;
    110      }
    111    } else {
    112      let row = document.createElement("tr");
    113      row.appendChild(col(policyName));
    114      row.appendChild(col(JSON.stringify(data[policyName])));
    115      row.classList.add(color_class, "last_row");
    116      new_cont.appendChild(row);
    117    }
    118  }
    119 
    120  if (policy_count < 1) {
    121    let current_tab = document.querySelector(".active");
    122    if (Services.policies.status == Services.policies.ACTIVE) {
    123      current_tab.classList.add("no-specified-policies");
    124    } else {
    125      current_tab.classList.add("inactive-service");
    126    }
    127  }
    128 
    129  addMissingColumns();
    130 }
    131 
    132 /*
    133 * This is a helper recursive function that iterates levels of each
    134 * policy and formats the content to be displayed accordingly.
    135 */
    136 
    137 function generatePolicy(data, row, depth, new_cont, islast, arr_sep = false) {
    138  const color_class = row.classList.contains("odd") ? "odd" : "even";
    139 
    140  if (Array.isArray(data)) {
    141    for (let count in data) {
    142      if (count == 0) {
    143        if (count == data.length - 1) {
    144          generatePolicy(
    145            data[count],
    146            row,
    147            depth + 1,
    148            new_cont,
    149            islast ? islast : false,
    150            true
    151          );
    152        } else {
    153          generatePolicy(data[count], row, depth + 1, new_cont, false, false);
    154        }
    155      } else if (count == data.length - 1) {
    156        let last_row = document.createElement("tr");
    157        last_row.classList.add(color_class, "arr_sep");
    158 
    159        for (let i = 0; i < depth; i++) {
    160          last_row.appendChild(col(""));
    161        }
    162 
    163        generatePolicy(
    164          data[count],
    165          last_row,
    166          depth + 1,
    167          new_cont,
    168          islast ? islast : false,
    169          arr_sep
    170        );
    171      } else {
    172        let new_row = document.createElement("tr");
    173        new_row.classList.add(color_class);
    174 
    175        for (let i = 0; i < depth; i++) {
    176          new_row.appendChild(col(""));
    177        }
    178 
    179        generatePolicy(data[count], new_row, depth + 1, new_cont, false, false);
    180      }
    181    }
    182  } else if (typeof data == "object" && Object.keys(data).length) {
    183    let count = 0;
    184    for (let obj in data) {
    185      if (count == 0) {
    186        row.appendChild(col(obj));
    187        if (count == Object.keys(data).length - 1) {
    188          generatePolicy(
    189            data[obj],
    190            row,
    191            depth + 1,
    192            new_cont,
    193            islast ? islast : false,
    194            arr_sep
    195          );
    196        } else {
    197          generatePolicy(data[obj], row, depth + 1, new_cont, false, false);
    198        }
    199      } else if (count == Object.keys(data).length - 1) {
    200        let last_row = document.createElement("tr");
    201        for (let i = 0; i < depth; i++) {
    202          last_row.appendChild(col(""));
    203        }
    204 
    205        last_row.appendChild(col(obj));
    206        last_row.classList.add(color_class);
    207 
    208        if (arr_sep) {
    209          last_row.classList.add("arr_sep");
    210        }
    211 
    212        generatePolicy(
    213          data[obj],
    214          last_row,
    215          depth + 1,
    216          new_cont,
    217          islast ? islast : false,
    218          false
    219        );
    220      } else {
    221        let new_row = document.createElement("tr");
    222        new_row.classList.add(color_class);
    223 
    224        for (let i = 0; i < depth; i++) {
    225          new_row.appendChild(col(""));
    226        }
    227 
    228        new_row.appendChild(col(obj));
    229        generatePolicy(data[obj], new_row, depth + 1, new_cont, false, false);
    230      }
    231      count++;
    232    }
    233  } else {
    234    row.appendChild(col(JSON.stringify(data)));
    235 
    236    if (arr_sep) {
    237      row.classList.add("arr_sep");
    238    }
    239    if (islast) {
    240      row.classList.add("last_row");
    241    }
    242    new_cont.appendChild(row);
    243  }
    244 }
    245 
    246 function generateErrors() {
    247  const consoleStorage = Cc["@mozilla.org/consoleAPI-storage;1"];
    248  const storage = consoleStorage.getService(Ci.nsIConsoleAPIStorage);
    249  const consoleEvents = storage.getEvents();
    250  const prefixes = [
    251    "Enterprise Policies",
    252    "JsonSchemaValidator",
    253    "Policies",
    254    "WindowsGPOParser",
    255    "Enterprise Policies Child",
    256    "BookmarksPolicies",
    257    "ProxyPolicies",
    258    "WebsiteFilter Policy",
    259    "macOSPoliciesParser",
    260  ];
    261 
    262  let new_cont = document.getElementById("errorsContent");
    263  new_cont.classList.add("errors");
    264 
    265  let flag = false;
    266  for (let err of consoleEvents) {
    267    if (prefixes.includes(err.prefix)) {
    268      flag = true;
    269      let row = document.createElement("tr");
    270      row.appendChild(col(err.arguments[0]));
    271      new_cont.appendChild(row);
    272    }
    273  }
    274  if (!flag) {
    275    let errors_tab = document.getElementById("category-errors");
    276    errors_tab.hidden = true;
    277  }
    278 }
    279 
    280 function generateDocumentation() {
    281  let new_cont = document.getElementById("documentationContent");
    282  new_cont.setAttribute("id", "documentationContent");
    283 
    284  // map specific policies to a different string ID, to allow updates to
    285  // existing descriptions
    286  let string_mapping = {
    287    BackgroundAppUpdate: "BackgroundAppUpdate2",
    288    Certificates: "CertificatesDescription",
    289    DisableFirefoxAccounts: "DisableFirefoxAccounts1",
    290    DisableMasterPasswordCreation: "DisablePrimaryPasswordCreation",
    291    DisableSetDesktopBackground: "DisableSetAsDesktopBackground",
    292    FirefoxHome: "FirefoxHome2",
    293    Permissions: "Permissions2",
    294    PopupBlocking: "PopupBlocking2",
    295    SanitizeOnShutdown: "SanitizeOnShutdown2",
    296    SecurityDevices: "SecurityDevices2",
    297    SkipTermsOfUse: "SkipTermsOfUse2",
    298    WindowsSSO: "Windows10SSO",
    299    BrowserDataBackup: "Backup",
    300  };
    301  let deprecated_policies = ["DisablePocket"];
    302 
    303  for (let policyName in schema.properties) {
    304    if (deprecated_policies.includes(policyName)) {
    305      continue;
    306    }
    307    let main_tbody = document.createElement("tbody");
    308    main_tbody.classList.add("collapsible");
    309    main_tbody.addEventListener("click", function () {
    310      let content = this.nextElementSibling;
    311      content.classList.toggle("content");
    312    });
    313    let row = document.createElement("tr");
    314    row.appendChild(link(policyName));
    315    let descriptionColumn = col("");
    316    let stringID = string_mapping[policyName] || policyName;
    317    document.l10n.setAttributes(descriptionColumn, `policy-${stringID}`);
    318    row.appendChild(descriptionColumn);
    319    main_tbody.appendChild(row);
    320    let sec_tbody = document.createElement("tbody");
    321    sec_tbody.classList.add("content");
    322    sec_tbody.classList.add("content-style");
    323    let schema_row = document.createElement("tr");
    324    if (schema.properties[policyName].properties) {
    325      let column = col(
    326        JSON.stringify(schema.properties[policyName].properties, null, 1),
    327        "schema"
    328      );
    329      column.colSpan = "2";
    330      schema_row.appendChild(column);
    331      sec_tbody.appendChild(schema_row);
    332    } else if (schema.properties[policyName].items) {
    333      let column = col(
    334        JSON.stringify(schema.properties[policyName], null, 1),
    335        "schema"
    336      );
    337      column.colSpan = "2";
    338      schema_row.appendChild(column);
    339      sec_tbody.appendChild(schema_row);
    340    } else {
    341      let column = col("type: " + schema.properties[policyName].type, "schema");
    342      column.colSpan = "2";
    343      schema_row.appendChild(column);
    344      sec_tbody.appendChild(schema_row);
    345      if (schema.properties[policyName].enum) {
    346        let enum_row = document.createElement("tr");
    347        column = col(
    348          "enum: " +
    349            JSON.stringify(schema.properties[policyName].enum, null, 1),
    350          "schema"
    351        );
    352        column.colSpan = "2";
    353        enum_row.appendChild(column);
    354        sec_tbody.appendChild(enum_row);
    355      }
    356    }
    357    new_cont.appendChild(main_tbody);
    358    new_cont.appendChild(sec_tbody);
    359  }
    360 }
    361 
    362 let gInited = false;
    363 window.onload = function () {
    364  if (gInited) {
    365    return;
    366  }
    367  gInited = true;
    368 
    369  let data = Services.policies.getActivePolicies();
    370  generateActivePolicies(data);
    371  generateErrors();
    372  generateDocumentation();
    373 
    374  // Event delegation on #categories-nav element
    375  let menu = document.getElementById("categories-nav");
    376  menu.addEventListener("change-view", e => show(e.target));
    377 
    378  if (location.hash) {
    379    let sectionButton = document.getElementById(
    380      "category-" + location.hash.substring(1)
    381    );
    382    if (sectionButton) {
    383      sectionButton.click();
    384    }
    385  }
    386 
    387  window.addEventListener("hashchange", function () {
    388    if (location.hash) {
    389      let sectionButton = document.getElementById(
    390        "category-" + location.hash.substring(1)
    391      );
    392      sectionButton.click();
    393    }
    394  });
    395 };
    396 
    397 function show(button) {
    398  let current_tab = document.querySelector(".active");
    399  let category = button.getAttribute("id").substring("category-".length);
    400  let content = document.getElementById(category);
    401  if (current_tab == content) {
    402    return;
    403  }
    404  saveScrollPosition(current_tab.id);
    405  current_tab.classList.remove("active");
    406  current_tab.hidden = true;
    407  content.classList.add("active");
    408  content.hidden = false;
    409 
    410  let title = document.getElementById("sectionTitle");
    411  title.textContent = button.textContent;
    412  location.hash = category;
    413  restoreScrollPosition(category);
    414 }
    415 
    416 const scrollPositions = {};
    417 function saveScrollPosition(category) {
    418  const mainContent = document.querySelector(".main-content");
    419  scrollPositions[category] = mainContent.scrollTop;
    420 }
    421 
    422 function restoreScrollPosition(category) {
    423  const scrollY = scrollPositions[category] || 0;
    424  const mainContent = document.querySelector(".main-content");
    425  mainContent.scrollTo(0, scrollY);
    426 }