tor-browser

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

browser_createWindowsShortcut.js (5403B)


      1 /* Any copyright is dedicated to the Public Domain.
      2 * http://creativecommons.org/publicdomain/zero/1.0/ */
      3 
      4 "use strict";
      5 
      6 ChromeUtils.defineESModuleGetters(this, {
      7  FileTestUtils: "resource://testing-common/FileTestUtils.sys.mjs",
      8  MockRegistrar: "resource://testing-common/MockRegistrar.sys.mjs",
      9 });
     10 
     11 const gBase = Services.dirsvc.get("ProfD", Ci.nsIFile);
     12 gBase.append("CreateWindowsShortcut");
     13 createDirectory(gBase);
     14 
     15 const gTmpDir = Services.dirsvc.get("TmpD", Ci.nsIFile);
     16 
     17 const gDirectoryServiceProvider = {
     18  getFile(prop, persistent) {
     19    persistent.value = false;
     20 
     21    // We only expect a narrow range of calls.
     22    let folder = gBase.clone();
     23    switch (prop) {
     24      case "Progs":
     25        folder.append("Programs");
     26        break;
     27      case "Desk":
     28        folder.append("Desktop");
     29        break;
     30      case "UpdRootD":
     31        // We really want DataRoot, but UpdateSubdir is what we usually get.
     32        folder.append("DataRoot");
     33        folder.append("UpdateDir");
     34        folder.append("UpdateSubdir");
     35        break;
     36      case "ProfD":
     37        // Used by test infrastructure.
     38        folder = folder.parent;
     39        break;
     40      case "TmpD":
     41        // Used by FileTestUtils.
     42        folder = gTmpDir;
     43        break;
     44      default:
     45        console.error(`Access to unexpected directory '${prop}'`);
     46        return Cr.NS_ERROR_FAILURE;
     47    }
     48 
     49    createDirectory(folder);
     50    return folder;
     51  },
     52  QueryInterface: ChromeUtils.generateQI([Ci.nsIDirectoryServiceProvider]),
     53 };
     54 
     55 add_setup(() => {
     56  Services.dirsvc
     57    .QueryInterface(Ci.nsIDirectoryService)
     58    .registerProvider(gDirectoryServiceProvider);
     59 });
     60 
     61 registerCleanupFunction(() => {
     62  gBase.remove(true);
     63  Services.dirsvc
     64    .QueryInterface(Ci.nsIDirectoryService)
     65    .unregisterProvider(gDirectoryServiceProvider);
     66 });
     67 
     68 add_task(async function test_CreateWindowsShortcut() {
     69  const DEST = "browser_createWindowsShortcut_TestFile.lnk";
     70 
     71  const file = FileTestUtils.getTempFile("program.exe");
     72  const iconPath = FileTestUtils.getTempFile("program.ico");
     73 
     74  let shortcut;
     75 
     76  const defaults = {
     77    shellService: Cc["@mozilla.org/toolkit/shell-service;1"].getService(),
     78    targetFile: file,
     79    iconFile: iconPath,
     80    description: "made by browser_createWindowsShortcut.js",
     81    aumid: "TESTTEST",
     82  };
     83 
     84  shortcut = Services.dirsvc.get("Progs", Ci.nsIFile);
     85  shortcut.append(DEST);
     86  await testShortcut({
     87    shortcutFile: shortcut,
     88    relativePath: DEST,
     89    specialFolder: "Programs",
     90    logHeader: "STARTMENU",
     91    ...defaults,
     92  });
     93 
     94  let subdir = Services.dirsvc.get("Progs", Ci.nsIFile);
     95  subdir.append("Shortcut Test");
     96  tryRemove(subdir);
     97 
     98  shortcut = subdir.clone();
     99  shortcut.append(DEST);
    100  await testShortcut({
    101    shortcutFile: shortcut,
    102    relativePath: "Shortcut Test\\" + DEST,
    103    specialFolder: "Programs",
    104    logHeader: "STARTMENU",
    105    ...defaults,
    106  });
    107  tryRemove(subdir);
    108 
    109  shortcut = Services.dirsvc.get("Desk", Ci.nsIFile);
    110  shortcut.append(DEST);
    111  await testShortcut({
    112    shortcutFile: shortcut,
    113    relativePath: DEST,
    114    specialFolder: "Desktop",
    115    logHeader: "DESKTOP",
    116    ...defaults,
    117  });
    118 });
    119 
    120 async function testShortcut({
    121  shortcutFile,
    122  relativePath,
    123  specialFolder,
    124  logHeader,
    125 
    126  // Generally provided by the defaults.
    127  shellService,
    128  targetFile,
    129  iconFile,
    130  description,
    131  aumid,
    132 }) {
    133  // If it already exists, remove it.
    134  tryRemove(shortcutFile);
    135 
    136  await shellService.createShortcut(
    137    targetFile,
    138    [],
    139    description,
    140    iconFile,
    141    0,
    142    aumid,
    143    specialFolder,
    144    relativePath
    145  );
    146  ok(
    147    shortcutFile.exists(),
    148    `${specialFolder}\\${relativePath}: Shortcut should exist`
    149  );
    150  ok(
    151    queryShortcutLog(relativePath, logHeader),
    152    `${specialFolder}\\${relativePath}: Shortcut log entry was added`
    153  );
    154  await shellService.deleteShortcut(specialFolder, relativePath);
    155  ok(
    156    !shortcutFile.exists(),
    157    `${specialFolder}\\${relativePath}: Shortcut does not exist after deleting`
    158  );
    159  ok(
    160    !queryShortcutLog(relativePath, logHeader),
    161    `${specialFolder}\\${relativePath}: Shortcut log entry was removed`
    162  );
    163 }
    164 
    165 function queryShortcutLog(aShortcutName, aSection) {
    166  const parserFactory = Cc[
    167    "@mozilla.org/xpcom/ini-parser-factory;1"
    168  ].createInstance(Ci.nsIINIParserFactory);
    169 
    170  const dir = Services.dirsvc.get("UpdRootD", Ci.nsIFile).parent.parent;
    171  const enumerator = dir.directoryEntries;
    172 
    173  for (const file of enumerator) {
    174    // We don't know the user's SID from JS-land, so just look at all of them.
    175    if (!file.path.match(/[^_]+_S[^_]*_shortcuts.ini/)) {
    176      continue;
    177    }
    178 
    179    const parser = parserFactory.createINIParser(file);
    180    parser.QueryInterface(Ci.nsIINIParser);
    181    parser.QueryInterface(Ci.nsIINIParserWriter);
    182 
    183    for (let i = 0; ; i++) {
    184      try {
    185        let string = parser.getString(aSection, `Shortcut${i}`);
    186        if (string == aShortcutName) {
    187          enumerator.close();
    188          return true;
    189        }
    190      } catch (e) {
    191        // The key didn't exist, stop here.
    192        break;
    193      }
    194    }
    195  }
    196 
    197  enumerator.close();
    198  return false;
    199 }
    200 
    201 function createDirectory(aFolder) {
    202  try {
    203    aFolder.create(Ci.nsIFile.DIRECTORY_TYPE, 0o755);
    204  } catch (e) {
    205    if (e.result != Cr.NS_ERROR_FILE_ALREADY_EXISTS) {
    206      throw e;
    207    }
    208  }
    209 }
    210 
    211 function tryRemove(file) {
    212  try {
    213    file.remove(false);
    214    return true;
    215  } catch (e) {
    216    return false;
    217  }
    218 }