Merge release/0.3.83: keep master in step with what shipped as 0.3.83
This commit is contained in:
commit
0044a157f0
3 changed files with 47 additions and 3 deletions
|
|
@ -249,6 +249,19 @@ async function fetchVerifiedPackage({ id, version, url, sha256, log }) {
|
||||||
return { status: "extract-failed", newVer: version, detail: e.message };
|
return { status: "extract-failed", newVer: version, detail: e.message };
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// No links of any kind. A community extension runs sandboxed with read
|
||||||
|
// access to its own folder, and Node's permission model follows links, so
|
||||||
|
// a packaged symlink or junction to the profile (passwords.vault, the
|
||||||
|
// wallet store) would be a way out. tar.exe only fails to create symlinks
|
||||||
|
// where Windows withholds the privilege; with Developer Mode it makes them.
|
||||||
|
const links = findLinks(tmpDir);
|
||||||
|
if (links.length) {
|
||||||
|
log(`updates: ${id}@${version} contains links (${links.slice(0, 3).join(", ")}), refusing`);
|
||||||
|
try { fs.rmSync(tmpFile, { force: true }); } catch {}
|
||||||
|
try { fs.rmSync(tmpDir, { recursive: true, force: true }); } catch {}
|
||||||
|
return { status: "extract-failed", newVer: version, detail: "package contains links" };
|
||||||
|
}
|
||||||
|
|
||||||
// A package may wrap everything in one top-level folder (tar -czf x.tgz my-ext);
|
// A package may wrap everything in one top-level folder (tar -czf x.tgz my-ext);
|
||||||
// unwrap it so addon.json sits at the root like the bundled add-ons.
|
// unwrap it so addon.json sits at the root like the bundled add-ons.
|
||||||
let root = tmpDir;
|
let root = tmpDir;
|
||||||
|
|
@ -266,6 +279,27 @@ async function fetchVerifiedPackage({ id, version, url, sha256, log }) {
|
||||||
return { ok: true, tmpDir: root, tmpTop: tmpDir, tmpFile, manifest: extracted };
|
return { ok: true, tmpDir: root, tmpTop: tmpDir, tmpFile, manifest: extracted };
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Every symlink, junction or hard-linked file under root (relative paths).
|
||||||
|
// lstat reports a junction as a symbolic link; it is not followed.
|
||||||
|
function findLinks(root) {
|
||||||
|
const out = [];
|
||||||
|
const walk = (dir, rel) => {
|
||||||
|
let entries = [];
|
||||||
|
try { entries = fs.readdirSync(dir, { withFileTypes: true }); } catch { return; }
|
||||||
|
for (const de of entries) {
|
||||||
|
const p = path.join(dir, de.name), r = rel ? rel + "/" + de.name : de.name;
|
||||||
|
let st;
|
||||||
|
try { st = fs.lstatSync(p); } catch { out.push(r); continue; }
|
||||||
|
if (st.isSymbolicLink()) { out.push(r); continue; }
|
||||||
|
if (st.isDirectory()) { walk(p, r); continue; }
|
||||||
|
if (st.isFile() && st.nlink > 1) out.push(r);
|
||||||
|
else if (!st.isFile()) out.push(r);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
walk(root, "");
|
||||||
|
return out;
|
||||||
|
}
|
||||||
|
|
||||||
// Move an extracted package into place (rename, with copy fallback across volumes).
|
// Move an extracted package into place (rename, with copy fallback across volumes).
|
||||||
function placeDir(from, to) {
|
function placeDir(from, to) {
|
||||||
try { fs.renameSync(from, to); }
|
try { fs.renameSync(from, to); }
|
||||||
|
|
@ -420,7 +454,7 @@ async function checkAndStageUpdates({ addonsDir, stagedDir, pubkeysHex, verifyPu
|
||||||
return { report };
|
return { report };
|
||||||
}
|
}
|
||||||
|
|
||||||
module.exports = { communityUpdateProblem,
|
module.exports = { communityUpdateProblem, findLinks,
|
||||||
cmpVer,
|
cmpVer,
|
||||||
promoteStagedUpdates,
|
promoteStagedUpdates,
|
||||||
checkAndStageUpdates,
|
checkAndStageUpdates,
|
||||||
|
|
|
||||||
|
|
@ -635,7 +635,17 @@ class AddonHost {
|
||||||
let mod;
|
let mod;
|
||||||
const holder = { active: null };
|
const holder = { active: null };
|
||||||
const sandboxed = this._shouldSandbox(manifest);
|
const sandboxed = this._shouldSandbox(manifest);
|
||||||
if (sandboxed) mod = this._sandboxModule(manifest, folder, mainPath, holder);
|
if (sandboxed) {
|
||||||
|
// The permission model follows links, so read access to a folder that
|
||||||
|
// holds a symlink, junction or hard link to the profile is read access
|
||||||
|
// to the profile. Installs refuse such packages; a folder that has one
|
||||||
|
// anyway (an older install, a hand edit) does not start.
|
||||||
|
const { findLinks } = require("./addon-updater.js");
|
||||||
|
const scratch = path.join(this.dataDir, ".sandbox", "scratch", manifest.id);
|
||||||
|
const links = [...findLinks(folder), ...(fs.existsSync(scratch) ? findLinks(scratch).map((r) => "scratch/" + r) : [])];
|
||||||
|
if (links.length) throw new Error(`not started: the extension folder contains links (${links.slice(0, 3).join(", ")})`);
|
||||||
|
mod = this._sandboxModule(manifest, folder, mainPath, holder);
|
||||||
|
}
|
||||||
else try {
|
else try {
|
||||||
// Bust the require cache so a manual reload picks up edits — cheap since
|
// Bust the require cache so a manual reload picks up edits — cheap since
|
||||||
// add-ons are small. When the version changed (a hot-applied update) the
|
// add-ons are small. When the version changed (a hot-applied update) the
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,6 @@
|
||||||
{
|
{
|
||||||
"name": "theseus-navigator",
|
"name": "theseus-navigator",
|
||||||
"version": "0.3.82",
|
"version": "0.3.83",
|
||||||
"license": "MPL-2.0",
|
"license": "MPL-2.0",
|
||||||
"description": "Theseus Navigator — a browser that follows the thread. By Silent Mode, a Deviant project.",
|
"description": "Theseus Navigator — a browser that follows the thread. By Silent Mode, a Deviant project.",
|
||||||
"author": "Silent Mode",
|
"author": "Silent Mode",
|
||||||
|
|
|
||||||
Loading…
Add table
Reference in a new issue