tor-browser

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

powershell.js (5475B)


      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 /*
      6 * Copyright (C) 2007, 2008 Apple Inc.  All rights reserved.
      7 * Copyright (C) 2008, 2009 Anthony Ricaud <rik@webkit.org>
      8 * Copyright (C) 2011 Google Inc. All rights reserved.
      9 * Copyright (C) 2022 Mozilla Foundation. All rights reserved.
     10 *
     11 * Redistribution and use in source and binary forms, with or without
     12 * modification, are permitted provided that the following conditions
     13 * are met:
     14 *
     15 * 1.  Redistributions of source code must retain the above copyright
     16 *     notice, this list of conditions and the following disclaimer.
     17 * 2.  Redistributions in binary form must reproduce the above copyright
     18 *     notice, this list of conditions and the following disclaimer in the
     19 *     documentation and/or other materials provided with the distribution.
     20 * 3.  Neither the name of Apple Computer, Inc. ("Apple") nor the names of
     21 *     its contributors may be used to endorse or promote products derived
     22 *     from this software without specific prior written permission.
     23 *
     24 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
     25 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
     26 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
     27 * DISCLAIMED. IN NO EVENT SHALL APPLE OR ITS CONTRIBUTORS BE LIABLE FOR ANY
     28 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
     29 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
     30 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
     31 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
     32 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
     33 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
     34 */
     35 
     36 // Utility to generate commands to invoke a request for powershell
     37 "use strict";
     38 
     39 // Some of these headers are passed in as seperate `Invoke-WebRequest` parameters so ignore
     40 // when building the headers list, others are not to neccesarily restrict the request.
     41 const IGNORED_HEADERS = [
     42  "connection",
     43  "proxy-connection",
     44  "content-length",
     45  "expect",
     46  "range",
     47  "host",
     48  "content-type",
     49  "user-agent",
     50  "cookie",
     51 ];
     52 /**
     53 * This escapes strings for the powershell command
     54 *
     55 * 1. Escape the backtick, dollar sign and the double quotes See https://www.rlmueller.net/PowerShellEscape.htm
     56 * 2. Convert any non printing ASCII characters found, using the ASCII code.
     57 */
     58 function escapeStr(str) {
     59  return `"${str
     60    .replace(/[`\$"]/g, "`$&")
     61    .replace(/[^\x20-\x7E]/g, char => "$([char]" + char.charCodeAt(0) + ")")}"`;
     62 }
     63 
     64 const PowerShell = {
     65  generateCommand(url, method, headers, postData, cookies) {
     66    const parameters = [];
     67 
     68    // Create a WebSession to pass the information about cookies
     69    // See https://learn.microsoft.com/en-us/powershell/module/microsoft.powershell.utility/invoke-webrequest?view=powershell-7.2#-websession
     70    const session = [];
     71    for (const { name, value, domain } of cookies) {
     72      if (!session.length) {
     73        session.push(
     74          "$session = New-Object Microsoft.PowerShell.Commands.WebRequestSession"
     75        );
     76      }
     77      session.push(
     78        `$session.Cookies.Add((New-Object System.Net.Cookie(${escapeStr(
     79          name
     80        )}, ${escapeStr(value)}, "/", ${escapeStr(
     81          domain || new URL(url).host
     82        )})))`
     83      );
     84    }
     85 
     86    parameters.push(`-Uri ${escapeStr(url)}`);
     87 
     88    if (method !== "GET") {
     89      parameters.push(`-Method ${escapeStr(method)}`);
     90    }
     91 
     92    if (session.length) {
     93      parameters.push("-WebSession $session");
     94    }
     95 
     96    const userAgent = headers.find(
     97      ({ name }) => name.toLowerCase() === "user-agent"
     98    );
     99    if (userAgent) {
    100      parameters.push("-UserAgent " + escapeStr(userAgent.value));
    101    }
    102 
    103    const headersStr = [];
    104    for (let { name, value } of headers) {
    105      // Translate any HTTP2 pseudo headers to HTTP headers
    106      name = name.replace(/^:/, "");
    107 
    108      if (IGNORED_HEADERS.includes(name.toLowerCase())) {
    109        continue;
    110      }
    111      headersStr.push(`${escapeStr(name)} = ${escapeStr(value)}`);
    112    }
    113    if (headersStr.length) {
    114      parameters.push(`-Headers @{\n${headersStr.join("\n  ")}\n}`);
    115    }
    116 
    117    const contentType = headers.find(
    118      header => header.name.toLowerCase() === "content-type"
    119    );
    120    if (contentType) {
    121      parameters.push("-ContentType " + escapeStr(contentType.value));
    122    }
    123 
    124    const formData = postData.text;
    125    if (formData) {
    126      // Encode bytes if any of the characters is not an ASCII printing character (not between Space character and ~ character)
    127      // a-zA-Z0-9 etc. See http://www.asciitable.com/
    128      const body = /[^\x20-\x7E]/.test(formData)
    129        ? "([System.Text.Encoding]::UTF8.GetBytes(" + escapeStr(formData) + "))"
    130        : escapeStr(formData);
    131      parameters.push("-Body " + body);
    132    }
    133 
    134    return `${
    135      session.length ? session.join("\n").concat("\n") : ""
    136      // -UseBasicParsing is added for backward compatibility.
    137      // See https://learn.microsoft.com/en-us/powershell/module/microsoft.powershell.utility/invoke-webrequest?view=powershell-7.2#-usebasicparsing
    138    }Invoke-WebRequest -UseBasicParsing ${parameters.join(" `\n")}`;
    139  },
    140 };
    141 
    142 exports.PowerShell = PowerShell;