727 lines
19 KiB
JavaScript
727 lines
19 KiB
JavaScript
/* Any copyright is dedicated to the Public Domain.
|
|
* http://creativecommons.org/publicdomain/zero/1.0/ */
|
|
/* import-globals-from browser_content_sandbox_utils.js */
|
|
"use strict";
|
|
|
|
const lazy = {};
|
|
|
|
/* getLibcConstants is only present on *nix */
|
|
ChromeUtils.defineLazyGetter(lazy, "LIBC", () =>
|
|
ChromeUtils.getLibcConstants()
|
|
);
|
|
|
|
// Test if the content process can create in $HOME, this should fail
|
|
async function createFileInHome() {
|
|
let browser = gBrowser.selectedBrowser;
|
|
let homeFile = fileInHomeDir();
|
|
let path = homeFile.path;
|
|
let fileCreated = await SpecialPowers.spawn(browser, [path], createFile);
|
|
ok(!fileCreated.ok, "creating a file in home dir failed");
|
|
is(
|
|
fileCreated.code,
|
|
Cr.NS_ERROR_FILE_ACCESS_DENIED,
|
|
"creating a file in home dir failed with access denied"
|
|
);
|
|
if (fileCreated.ok) {
|
|
// content process successfully created the file, now remove it
|
|
homeFile.remove(false);
|
|
}
|
|
}
|
|
|
|
// Test if the content process can create a temp file, this is forbidden on all
|
|
// platforms. Also test that the content process cannot create symlinks on
|
|
// macOS/Linux or delete files.
|
|
async function createTempFile() {
|
|
// On Windows we allow access to the temp dir for DEBUG builds, because of
|
|
// logging that uses that dir.
|
|
let isDbgWin = isWin() && SpecialPowers.isDebugBuild;
|
|
|
|
let browser = gBrowser.selectedBrowser;
|
|
let path = fileInTempDir().path;
|
|
let fileCreated = await SpecialPowers.spawn(browser, [path], createFile);
|
|
if (isDbgWin) {
|
|
ok(fileCreated.ok, "creating a file in temp suceeded");
|
|
} else {
|
|
ok(!fileCreated.ok, "creating a file in temp failed");
|
|
is(
|
|
fileCreated.code,
|
|
Cr.NS_ERROR_FILE_ACCESS_DENIED,
|
|
"creating a file in temp failed with access denied"
|
|
);
|
|
}
|
|
|
|
// now delete the file
|
|
let fileDeleted = await SpecialPowers.spawn(browser, [path], deleteFile);
|
|
if (isDbgWin) {
|
|
ok(fileDeleted.ok, "deleting a file in temp succeeded");
|
|
} else {
|
|
ok(!fileDeleted.ok, "deleting a file in temp failed");
|
|
const expectedError = isLinux()
|
|
? Cr.NS_ERROR_FILE_ACCESS_DENIED
|
|
: Cr.NS_ERROR_FILE_NOT_FOUND;
|
|
is(
|
|
fileDeleted.code,
|
|
expectedError,
|
|
"deleting a file in temp failed with access denied"
|
|
);
|
|
}
|
|
|
|
// Test that symlink creation is not allowed on macOS/Linux.
|
|
if (isMac() || isLinux()) {
|
|
let path = fileInTempDir().path;
|
|
let symlinkCreated = await SpecialPowers.spawn(
|
|
browser,
|
|
[path],
|
|
createSymlink
|
|
);
|
|
ok(!symlinkCreated.ok, "created a symlink in temp failed");
|
|
const expectedError = isLinux() ? lazy.LIBC.EACCES : lazy.LIBC.EPERM;
|
|
is(
|
|
symlinkCreated.code,
|
|
expectedError,
|
|
"created a symlink in temp failed with access denied"
|
|
);
|
|
}
|
|
}
|
|
|
|
// Test reading files and dirs from web and file content processes.
|
|
async function testFileAccessAllPlatforms() {
|
|
let webBrowser = GetWebBrowser();
|
|
let fileContentProcessEnabled = isFileContentProcessEnabled();
|
|
let fileBrowser = GetFileBrowser();
|
|
|
|
// Directories/files to test accessing from content processes.
|
|
// For directories, we test whether a directory listing is allowed
|
|
// or blocked. For files, we test if we can read from the file.
|
|
// Each entry in the array represents a test file or directory
|
|
// that will be read from either a web or file process.
|
|
let tests = [];
|
|
|
|
let profileDir = GetProfileDir();
|
|
tests.push({
|
|
desc: "profile dir", // description
|
|
ok: false, // expected to succeed?
|
|
browser: webBrowser, // browser to run test in
|
|
file: profileDir, // nsIFile object
|
|
minLevel: minProfileReadSandboxLevel(), // min level to enable test
|
|
func: readDir,
|
|
});
|
|
if (fileContentProcessEnabled) {
|
|
tests.push({
|
|
desc: "profile dir",
|
|
ok: true,
|
|
browser: fileBrowser,
|
|
file: profileDir,
|
|
minLevel: 0,
|
|
func: readDir,
|
|
});
|
|
}
|
|
|
|
let homeDir = GetHomeDir();
|
|
tests.push({
|
|
desc: "home dir",
|
|
ok: false,
|
|
browser: webBrowser,
|
|
file: homeDir,
|
|
minLevel: minHomeReadSandboxLevel(),
|
|
func: readDir,
|
|
});
|
|
if (fileContentProcessEnabled) {
|
|
tests.push({
|
|
desc: "home dir",
|
|
ok: true,
|
|
browser: fileBrowser,
|
|
file: homeDir,
|
|
minLevel: 0,
|
|
func: readDir,
|
|
});
|
|
}
|
|
|
|
let extensionsDir = GetProfileEntry("extensions");
|
|
if (extensionsDir.exists() && extensionsDir.isDirectory()) {
|
|
tests.push({
|
|
desc: "extensions dir",
|
|
ok: true,
|
|
browser: webBrowser,
|
|
file: extensionsDir,
|
|
minLevel: 0,
|
|
func: readDir,
|
|
});
|
|
} else {
|
|
ok(false, `${extensionsDir.path} is a valid dir`);
|
|
}
|
|
|
|
let chromeDir = GetProfileEntry("chrome");
|
|
if (chromeDir.exists() && chromeDir.isDirectory()) {
|
|
tests.push({
|
|
desc: "chrome dir",
|
|
ok: true,
|
|
browser: webBrowser,
|
|
file: chromeDir,
|
|
minLevel: 0,
|
|
func: readDir,
|
|
});
|
|
} else {
|
|
ok(false, `${chromeDir.path} is valid dir`);
|
|
}
|
|
|
|
let cookiesFile = GetProfileEntry("cookies.sqlite");
|
|
if (cookiesFile.exists() && !cookiesFile.isDirectory()) {
|
|
tests.push({
|
|
desc: "cookies file",
|
|
ok: false,
|
|
browser: webBrowser,
|
|
file: cookiesFile,
|
|
minLevel: minProfileReadSandboxLevel(),
|
|
func: readFile,
|
|
});
|
|
if (fileContentProcessEnabled) {
|
|
tests.push({
|
|
desc: "cookies file",
|
|
ok: true,
|
|
browser: fileBrowser,
|
|
file: cookiesFile,
|
|
minLevel: 0,
|
|
func: readFile,
|
|
});
|
|
}
|
|
} else {
|
|
ok(false, `${cookiesFile.path} is a valid file`);
|
|
}
|
|
|
|
if (isMac() || isLinux()) {
|
|
let varDir = GetDir("/var");
|
|
|
|
if (isMac()) {
|
|
// Mac sandbox rules use /private/var because /var is a symlink
|
|
// to /private/var on OS X. Make sure that hasn't changed.
|
|
varDir.normalize();
|
|
Assert.ok(
|
|
varDir.path === "/private/var",
|
|
"/var resolves to /private/var"
|
|
);
|
|
}
|
|
|
|
tests.push({
|
|
desc: "/var",
|
|
ok: false,
|
|
browser: webBrowser,
|
|
file: varDir,
|
|
minLevel: minHomeReadSandboxLevel(),
|
|
func: readDir,
|
|
});
|
|
if (fileContentProcessEnabled) {
|
|
tests.push({
|
|
desc: "/var",
|
|
ok: true,
|
|
browser: fileBrowser,
|
|
file: varDir,
|
|
minLevel: 0,
|
|
func: readDir,
|
|
});
|
|
}
|
|
}
|
|
|
|
await runTestsList(tests);
|
|
}
|
|
|
|
async function testFileAccessMacOnly() {
|
|
if (!isMac()) {
|
|
return;
|
|
}
|
|
|
|
let webBrowser = GetWebBrowser();
|
|
let fileContentProcessEnabled = isFileContentProcessEnabled();
|
|
let fileBrowser = GetFileBrowser();
|
|
let level = GetSandboxLevel();
|
|
|
|
let tests = [];
|
|
|
|
// If ~/Library/Caches/TemporaryItems exists, when level <= 2 we
|
|
// make sure it's readable. For level 3, we make sure it isn't.
|
|
let homeTempDir = GetHomeDir();
|
|
homeTempDir.appendRelativePath("Library/Caches/TemporaryItems");
|
|
if (homeTempDir.exists()) {
|
|
let shouldBeReadable, minLevel;
|
|
if (level >= minHomeReadSandboxLevel()) {
|
|
shouldBeReadable = false;
|
|
minLevel = minHomeReadSandboxLevel();
|
|
} else {
|
|
shouldBeReadable = true;
|
|
minLevel = 0;
|
|
}
|
|
tests.push({
|
|
desc: "home library cache temp dir",
|
|
ok: shouldBeReadable,
|
|
browser: webBrowser,
|
|
file: homeTempDir,
|
|
minLevel,
|
|
func: readDir,
|
|
});
|
|
}
|
|
|
|
// Test if we can read from $TMPDIR because we expect it
|
|
// to be within /private/var. Reading from it should be
|
|
// prevented in a 'web' process.
|
|
let macTempDir = GetDirFromEnvVariable("TMPDIR");
|
|
|
|
macTempDir.normalize();
|
|
Assert.ok(
|
|
macTempDir.path.startsWith("/private/var"),
|
|
"$TMPDIR is in /private/var"
|
|
);
|
|
|
|
tests.push({
|
|
desc: `$TMPDIR (${macTempDir.path})`,
|
|
ok: false,
|
|
browser: webBrowser,
|
|
file: macTempDir,
|
|
minLevel: minHomeReadSandboxLevel(),
|
|
func: readDir,
|
|
});
|
|
if (fileContentProcessEnabled) {
|
|
tests.push({
|
|
desc: `$TMPDIR (${macTempDir.path})`,
|
|
ok: true,
|
|
browser: fileBrowser,
|
|
file: macTempDir,
|
|
minLevel: 0,
|
|
func: readDir,
|
|
});
|
|
}
|
|
|
|
// The font registry directory is in the Darwin user cache dir which is
|
|
// accessible with the getconf(1) library call using DARWIN_USER_CACHE_DIR.
|
|
// For this test, assume the cache dir is located at $TMPDIR/../C and use
|
|
// the $TMPDIR to derive the path to the registry.
|
|
let fontRegistryDir = macTempDir.parent.clone();
|
|
fontRegistryDir.appendRelativePath("C/com.apple.FontRegistry");
|
|
if (fontRegistryDir.exists()) {
|
|
tests.push({
|
|
desc: `FontRegistry (${fontRegistryDir.path})`,
|
|
ok: true,
|
|
browser: webBrowser,
|
|
file: fontRegistryDir,
|
|
minLevel: minHomeReadSandboxLevel(),
|
|
func: readDir,
|
|
});
|
|
// Check that we can read the file named `font` which typically
|
|
// exists in the the font registry directory.
|
|
let fontFile = fontRegistryDir.clone();
|
|
fontFile.appendRelativePath("font");
|
|
if (fontFile.exists()) {
|
|
tests.push({
|
|
desc: `FontRegistry file (${fontFile.path})`,
|
|
ok: true,
|
|
browser: webBrowser,
|
|
file: fontFile,
|
|
minLevel: minHomeReadSandboxLevel(),
|
|
func: readFile,
|
|
});
|
|
}
|
|
}
|
|
|
|
// Test that we cannot read from /Volumes at level 3
|
|
let volumes = GetDir("/Volumes");
|
|
tests.push({
|
|
desc: "/Volumes",
|
|
ok: false,
|
|
browser: webBrowser,
|
|
file: volumes,
|
|
minLevel: minHomeReadSandboxLevel(),
|
|
func: readDir,
|
|
});
|
|
|
|
// /Network is not present on macOS 10.15 (xnu 19). Don't
|
|
// test this directory on 10.15 and later.
|
|
if (AppConstants.isPlatformAndVersionAtMost("macosx", 18)) {
|
|
// Test that we cannot read from /Network at level 3
|
|
let network = GetDir("/Network");
|
|
tests.push({
|
|
desc: "/Network",
|
|
ok: false,
|
|
browser: webBrowser,
|
|
file: network,
|
|
minLevel: minHomeReadSandboxLevel(),
|
|
func: readDir,
|
|
});
|
|
}
|
|
// Test that we cannot read from /Users at level 3
|
|
let users = GetDir("/Users");
|
|
tests.push({
|
|
desc: "/Users",
|
|
ok: false,
|
|
browser: webBrowser,
|
|
file: users,
|
|
minLevel: minHomeReadSandboxLevel(),
|
|
func: readDir,
|
|
});
|
|
|
|
// Test that we can stat /Users at level 3
|
|
tests.push({
|
|
desc: "/Users",
|
|
ok: true,
|
|
browser: webBrowser,
|
|
file: users,
|
|
minLevel: minHomeReadSandboxLevel(),
|
|
func: statPath,
|
|
});
|
|
|
|
// Test that we can stat /Library at level 3, but can't get a
|
|
// directory listing of /Library. This test uses "/Library"
|
|
// because it's a path that is expected to always be present.
|
|
let libraryDir = GetDir("/Library");
|
|
tests.push({
|
|
desc: "/Library",
|
|
ok: true,
|
|
browser: webBrowser,
|
|
file: libraryDir,
|
|
minLevel: minHomeReadSandboxLevel(),
|
|
func: statPath,
|
|
});
|
|
tests.push({
|
|
desc: "/Library",
|
|
ok: false,
|
|
browser: webBrowser,
|
|
file: libraryDir,
|
|
minLevel: minHomeReadSandboxLevel(),
|
|
func: readDir,
|
|
});
|
|
|
|
// Similarly, test that we can stat /private, but not /private/etc.
|
|
let privateDir = GetDir("/private");
|
|
tests.push({
|
|
desc: "/private",
|
|
ok: true,
|
|
browser: webBrowser,
|
|
file: privateDir,
|
|
minLevel: minHomeReadSandboxLevel(),
|
|
func: statPath,
|
|
});
|
|
|
|
await runTestsList(tests);
|
|
}
|
|
|
|
async function testFileAccessLinuxOnly() {
|
|
if (!isLinux()) {
|
|
return;
|
|
}
|
|
|
|
let webBrowser = GetWebBrowser();
|
|
let fileContentProcessEnabled = isFileContentProcessEnabled();
|
|
let fileBrowser = GetFileBrowser();
|
|
|
|
let tests = [];
|
|
|
|
// Test /proc/self/fd, because that can be used to unfreeze
|
|
// frozen shared memory.
|
|
let selfFdDir = GetDir("/proc/self/fd");
|
|
tests.push({
|
|
desc: "/proc/self/fd",
|
|
ok: false,
|
|
browser: webBrowser,
|
|
file: selfFdDir,
|
|
minLevel: isContentFileIOSandboxed(),
|
|
func: readDir,
|
|
});
|
|
|
|
let cacheFontConfigDir = GetHomeSubdir(".cache/fontconfig/");
|
|
tests.push({
|
|
desc: `$HOME/.cache/fontconfig/ (${cacheFontConfigDir.path})`,
|
|
ok: true,
|
|
browser: webBrowser,
|
|
file: cacheFontConfigDir,
|
|
minLevel: minHomeReadSandboxLevel(),
|
|
func: readDir,
|
|
});
|
|
|
|
// allows to handle both $HOME/.config/ or $XDG_CONFIG_HOME
|
|
let configDir = GetHomeSubdir(".config");
|
|
|
|
const xdgConfigHome = Services.env.get("XDG_CONFIG_HOME");
|
|
|
|
if (xdgConfigHome.length > 1) {
|
|
configDir = GetDir(xdgConfigHome);
|
|
configDir.normalize();
|
|
|
|
tests.push({
|
|
desc: `$XDG_CONFIG_HOME (${configDir.path})`,
|
|
ok: true,
|
|
browser: webBrowser,
|
|
file: configDir,
|
|
minLevel: minHomeReadSandboxLevel(),
|
|
func: readDir,
|
|
});
|
|
}
|
|
|
|
// $HOME/.config/ or $XDG_CONFIG_HOME/ should have rdonly access
|
|
tests.push({
|
|
desc: `${configDir.path} dir`,
|
|
ok: true,
|
|
browser: webBrowser,
|
|
file: configDir,
|
|
minLevel: minHomeReadSandboxLevel(),
|
|
func: readDir,
|
|
});
|
|
if (fileContentProcessEnabled) {
|
|
tests.push({
|
|
desc: `${configDir.path} dir`,
|
|
ok: true,
|
|
browser: fileBrowser,
|
|
file: configDir,
|
|
minLevel: 0,
|
|
func: readDir,
|
|
});
|
|
}
|
|
|
|
if (xdgConfigHome.length > 1) {
|
|
// When XDG_CONFIG_HOME is set, dont allow $HOME/.config
|
|
const homeConfigDir = GetHomeSubdir(".config");
|
|
tests.push({
|
|
desc: `${homeConfigDir.path} dir`,
|
|
ok: false,
|
|
browser: webBrowser,
|
|
file: homeConfigDir,
|
|
minLevel: minHomeReadSandboxLevel(),
|
|
func: readDir,
|
|
});
|
|
if (fileContentProcessEnabled) {
|
|
tests.push({
|
|
desc: `${homeConfigDir.path} dir`,
|
|
ok: true,
|
|
browser: fileBrowser,
|
|
file: homeConfigDir,
|
|
minLevel: 0,
|
|
func: readDir,
|
|
});
|
|
}
|
|
} else {
|
|
// WWhen XDG_CONFIG_HOME is not set, verify we do not allow $HOME/.configlol
|
|
// (i.e., check allow the dir and not the prefix)
|
|
//
|
|
// Checking $HOME/.config is already done above.
|
|
const homeConfigPrefix = GetHomeSubdir(".configlol");
|
|
tests.push({
|
|
desc: `${homeConfigPrefix.path} dir`,
|
|
ok: false,
|
|
browser: webBrowser,
|
|
file: homeConfigPrefix,
|
|
minLevel: minHomeReadSandboxLevel(),
|
|
func: readDir,
|
|
});
|
|
if (fileContentProcessEnabled) {
|
|
tests.push({
|
|
desc: `${homeConfigPrefix.path} dir`,
|
|
ok: false,
|
|
browser: fileBrowser,
|
|
file: homeConfigPrefix,
|
|
minLevel: 0,
|
|
func: readDir,
|
|
});
|
|
}
|
|
}
|
|
|
|
// Create a file under $HOME/.config/ or $XDG_CONFIG_HOME and ensure we can
|
|
// read it
|
|
let fileUnderConfig = GetSubdirFile(configDir);
|
|
await IOUtils.writeUTF8(fileUnderConfig.path, "TEST FILE DUMMY DATA");
|
|
ok(
|
|
await IOUtils.exists(fileUnderConfig.path),
|
|
`File ${fileUnderConfig.path} was properly created`
|
|
);
|
|
|
|
tests.push({
|
|
desc: `${configDir.path}/xxx is readable (${fileUnderConfig.path})`,
|
|
ok: true,
|
|
browser: webBrowser,
|
|
file: fileUnderConfig,
|
|
minLevel: minHomeReadSandboxLevel(),
|
|
func: readFile,
|
|
cleanup: aPath => IOUtils.remove(aPath),
|
|
});
|
|
|
|
let configFile = GetSubdirFile(configDir);
|
|
tests.push({
|
|
desc: `${configDir.path} file write`,
|
|
ok: false,
|
|
browser: webBrowser,
|
|
file: configFile,
|
|
minLevel: minHomeReadSandboxLevel(),
|
|
func: createFile,
|
|
});
|
|
if (fileContentProcessEnabled) {
|
|
tests.push({
|
|
desc: `${configDir.path} file write`,
|
|
ok: false,
|
|
browser: fileBrowser,
|
|
file: configFile,
|
|
minLevel: 0,
|
|
func: createFile,
|
|
});
|
|
}
|
|
|
|
// Create a $HOME/.config/mozilla/ or $XDG_CONFIG_HOME/mozilla/ if none
|
|
// exists and assert content process cannot access it
|
|
let configMozilla = GetSubdir(configDir, "mozilla");
|
|
const emptyFileName = ".test_run_browser_sandbox.tmp";
|
|
let emptyFile = configMozilla.clone();
|
|
emptyFile.appendRelativePath(emptyFileName);
|
|
|
|
let populateFakeConfigMozilla = async aPath => {
|
|
// called with configMozilla
|
|
await IOUtils.makeDirectory(aPath, { permissions: 0o700 });
|
|
await IOUtils.writeUTF8(emptyFile.path, "");
|
|
ok(
|
|
await IOUtils.exists(emptyFile.path),
|
|
`Temp file ${emptyFile.path} was created`
|
|
);
|
|
};
|
|
|
|
let unpopulateFakeConfigMozilla = async aPath => {
|
|
// called with emptyFile
|
|
await IOUtils.remove(aPath);
|
|
ok(!(await IOUtils.exists(aPath)), `Temp file ${aPath} was removed`);
|
|
const parentDir = PathUtils.parent(aPath);
|
|
try {
|
|
await IOUtils.remove(parentDir, { recursive: false });
|
|
} catch (ex) {
|
|
if (
|
|
!DOMException.isInstance(ex) ||
|
|
ex.name !== "OperationError" ||
|
|
/Could not remove the non-empty directory/.test(ex.message)
|
|
) {
|
|
// If we get here it means the directory was not empty and since we assert
|
|
// earlier we removed the temp file we created it means we should not
|
|
// worrying about removing this directory ...
|
|
throw ex;
|
|
}
|
|
}
|
|
};
|
|
|
|
await populateFakeConfigMozilla(configMozilla.path);
|
|
|
|
tests.push({
|
|
desc: `stat ${configDir.path}/mozilla (${configMozilla.path})`,
|
|
ok: false,
|
|
browser: webBrowser,
|
|
file: configMozilla,
|
|
minLevel: minHomeReadSandboxLevel(),
|
|
func: statPath,
|
|
});
|
|
|
|
tests.push({
|
|
desc: `read ${configDir.path}/mozilla (${configMozilla.path})`,
|
|
ok: false,
|
|
browser: webBrowser,
|
|
file: configMozilla,
|
|
minLevel: minHomeReadSandboxLevel(),
|
|
func: readDir,
|
|
});
|
|
|
|
tests.push({
|
|
desc: `stat ${configDir.path}/mozilla/${emptyFileName} (${emptyFile.path})`,
|
|
ok: false,
|
|
browser: webBrowser,
|
|
file: emptyFile,
|
|
minLevel: minHomeReadSandboxLevel(),
|
|
func: statPath,
|
|
});
|
|
|
|
tests.push({
|
|
desc: `read ${configDir.path}/mozilla/${emptyFileName} (${emptyFile.path})`,
|
|
ok: false,
|
|
browser: webBrowser,
|
|
file: emptyFile,
|
|
minLevel: minHomeReadSandboxLevel(),
|
|
func: readFile,
|
|
cleanup: unpopulateFakeConfigMozilla,
|
|
});
|
|
|
|
// Only needed to perform cleanup
|
|
if (xdgConfigHome.length > 1) {
|
|
tests.push({
|
|
desc: `$XDG_CONFIG_HOME (${configDir.path}) cleanup`,
|
|
ok: true,
|
|
browser: webBrowser,
|
|
file: configDir,
|
|
minLevel: minHomeReadSandboxLevel(),
|
|
func: readDir,
|
|
});
|
|
}
|
|
|
|
await runTestsList(tests);
|
|
}
|
|
|
|
async function testFileAccessLinuxSnap() {
|
|
let webBrowser = GetWebBrowser();
|
|
|
|
let tests = [];
|
|
|
|
// Assert that if we run with SNAP= env, then we allow access to it in the
|
|
// content process
|
|
let snap = Services.env.get("SNAP");
|
|
let snapExpectedResult = false;
|
|
if (snap.length > 1) {
|
|
snapExpectedResult = true;
|
|
} else {
|
|
snap = "/tmp/.snap_firefox_current/";
|
|
}
|
|
|
|
let snapDir = GetDir(snap);
|
|
snapDir.normalize();
|
|
|
|
let snapFile = GetSubdirFile(snapDir);
|
|
await createFile(snapFile.path);
|
|
ok(await IOUtils.exists(snapFile.path), `SNAP ${snapFile.path} was created`);
|
|
info(`SNAP (file) ${snapFile.path} was created`);
|
|
|
|
tests.push({
|
|
desc: `$SNAP (${snapDir.path} => ${snapFile.path})`,
|
|
ok: snapExpectedResult,
|
|
browser: webBrowser,
|
|
file: snapFile,
|
|
minLevel: minHomeReadSandboxLevel(),
|
|
func: readFile,
|
|
});
|
|
|
|
await runTestsList(tests);
|
|
}
|
|
|
|
async function testFileAccessWindowsOnly() {
|
|
if (!isWin()) {
|
|
return;
|
|
}
|
|
|
|
let webBrowser = GetWebBrowser();
|
|
|
|
let tests = [];
|
|
|
|
let extDir = GetPerUserExtensionDir();
|
|
tests.push({
|
|
desc: "per-user extensions dir",
|
|
ok: true,
|
|
browser: webBrowser,
|
|
file: extDir,
|
|
minLevel: minHomeReadSandboxLevel(),
|
|
func: readDir,
|
|
});
|
|
|
|
await runTestsList(tests);
|
|
}
|
|
|
|
function cleanupBrowserTabs() {
|
|
let fileBrowser = GetFileBrowser();
|
|
if (fileBrowser.selectedTab) {
|
|
gBrowser.removeTab(fileBrowser.selectedTab);
|
|
}
|
|
|
|
let webBrowser = GetWebBrowser();
|
|
if (webBrowser.selectedTab) {
|
|
gBrowser.removeTab(webBrowser.selectedTab);
|
|
}
|
|
|
|
let tab1 = gBrowser.tabs[1];
|
|
if (tab1) {
|
|
gBrowser.removeTab(tab1);
|
|
}
|
|
}
|