From d8bbc7858622b6d9c278469aab701ca0b609cddf Mon Sep 17 00:00:00 2001 From: Daniel Baumann Date: Wed, 15 May 2024 05:35:49 +0200 Subject: Merging upstream version 126.0. Signed-off-by: Daniel Baumann --- dom/manifest/Manifest.sys.mjs | 37 +++++++++++++++++++--- dom/manifest/test/browser_Manifest_install.js | 45 +++++++++++++++++++++++++-- 2 files changed, 76 insertions(+), 6 deletions(-) (limited to 'dom/manifest') diff --git a/dom/manifest/Manifest.sys.mjs b/dom/manifest/Manifest.sys.mjs index 15e1e2ef93..97f786318f 100644 --- a/dom/manifest/Manifest.sys.mjs +++ b/dom/manifest/Manifest.sys.mjs @@ -29,11 +29,11 @@ ChromeUtils.defineESModuleGetters(lazy, { * @note The generated hash is returned in base64 form. Mind the fact base64 * is case-sensitive if you are going to reuse this code. */ -function generateHash(aString) { +function generateHash(aString, hashAlg) { const cryptoHash = Cc["@mozilla.org/security/hash;1"].createInstance( Ci.nsICryptoHash ); - cryptoHash.init(Ci.nsICryptoHash.MD5); + cryptoHash.init(hashAlg); const stringStream = Cc[ "@mozilla.org/io/string-input-stream;1" ].createInstance(Ci.nsIStringInputStream); @@ -66,11 +66,39 @@ class Manifest { this._manifestUrl = manifestUrl; // The key for this is the manifests URL that is required to be unique. // However arbitrary urls are not safe file paths so lets hash it. - const fileName = generateHash(manifestUrl) + ".json"; - this._path = PathUtils.join(MANIFESTS_DIR, fileName); + const filename = + generateHash(manifestUrl, Ci.nsICryptoHash.SHA256) + ".json"; + this._path = PathUtils.join(MANIFESTS_DIR, filename); this.browser = browser; } + /** + * See Bug 1871109 + * This function is called at the beginning of initialize() to check if a given + * manifest has MD5 based filename, if so we remove it and migrate the content to + * a new file with SHA256 based name. + * This is done due to security concern, as MD5 is an outdated hashing algorithm and + * shouldn't be used anymore + */ + async removeMD5BasedFilename() { + const filenameMD5 = + generateHash(this._manifestUrl, Ci.nsICryptoHash.MD5) + ".json"; + const MD5Path = PathUtils.join(MANIFESTS_DIR, filenameMD5); + try { + await IOUtils.copy(MD5Path, this._path, { noOverwrite: true }); + } catch (error) { + // we are ignoring the failures returned from copy as it should not stop us from + // installing a new manifest + } + + // Remove the old MD5 based file unconditionally to ensure it's no longer used + try { + await IOUtils.remove(MD5Path); + } catch { + // ignore the error in case MD5 based file does not exist + } + } + get browser() { return this._browser; } @@ -80,6 +108,7 @@ class Manifest { } async initialize() { + await this.removeMD5BasedFilename(); this._store = new lazy.JSONFile({ path: this._path, saveDelayMs: 100 }); await this._store.load(); } diff --git a/dom/manifest/test/browser_Manifest_install.js b/dom/manifest/test/browser_Manifest_install.js index d3b949be19..aad43e0263 100644 --- a/dom/manifest/test/browser_Manifest_install.js +++ b/dom/manifest/test/browser_Manifest_install.js @@ -23,18 +23,59 @@ function makeTestURL() { return url.href; } +function generateHash(aString, hashAlg) { + const cryptoHash = Cc["@mozilla.org/security/hash;1"].createInstance( + Ci.nsICryptoHash + ); + cryptoHash.init(hashAlg); + const stringStream = Cc[ + "@mozilla.org/io/string-input-stream;1" + ].createInstance(Ci.nsIStringInputStream); + stringStream.data = aString; + cryptoHash.updateFromStream(stringStream, -1); + // base64 allows the '/' char, but we can't use it for filenames. + return cryptoHash.finish(true).replace(/\//g, "-"); +} + +const MANIFESTS_DIR = PathUtils.join(PathUtils.profileDir, "manifests"); + add_task(async function () { const tabOptions = { gBrowser, url: makeTestURL() }; + const filenameMD5 = generateHash(manifestUrl, Ci.nsICryptoHash.MD5) + ".json"; + const filenameSHA = + generateHash(manifestUrl, Ci.nsICryptoHash.SHA256) + ".json"; + const manifestMD5Path = PathUtils.join(MANIFESTS_DIR, filenameMD5); + const manifestSHAPath = PathUtils.join(MANIFESTS_DIR, filenameSHA); + await BrowserTestUtils.withNewTab(tabOptions, async function (browser) { - let manifest = await Manifests.getManifest(browser, manifestUrl); - is(manifest.installed, false, "We haven't installed this manifest yet"); + let tmpManifest = await Manifests.getManifest(browser, manifestUrl); + is(tmpManifest.installed, false, "We haven't installed this manifest yet"); + + await tmpManifest.install(); + // making sure the manifest is actually installed before proceeding + await tmpManifest._store._save(); + await IOUtils.move(tmpManifest.path, manifestMD5Path); + + let exists = await IOUtils.exists(tmpManifest.path); + is( + exists, + false, + "Manually moved manifest from SHA256 based path to MD5 based path" + ); + Manifests.manifestObjs.delete(manifestUrl); + + let manifest = await Manifests.getManifest(browser, manifestUrl); await manifest.install(browser); is(manifest.name, "hello World", "Manifest has correct name"); is(manifest.installed, true, "Manifest is installed"); is(manifest.url, manifestUrl, "has correct url"); is(manifest.browser, browser, "has correct browser"); + is(manifest.path, manifestSHAPath, "has correct path"); + + exists = await IOUtils.exists(manifestMD5Path); + is(exists, false, "MD5 based manifest removed"); manifest = await Manifests.getManifest(browser, manifestUrl); is(manifest.installed, true, "New instances are installed"); -- cgit v1.2.3