Background
I would like to add crates.io to Firefox Quantum but got an error saying that it cannot add it via https://crates.io/opensearch.xml
So here comes a short note of manually adding a search engine to Firefox Quantum.
Step 1: Extract search.json.mozlz4
Definitions of installed search engines are stored in the file search.json.mozlz4 which is located in your profile folder. Under Linux it’s usually ~/.mozilla/firefox/XXXXXXXX.default. If you’re unsure about it, run firefox -profilemanager (or firefox-developer-edition -profilemanager) to find it out.
To decompress this file, a small Python script MozLz4a compression/decompression utility can do us a favour. Note that as mentioned in the comments, you may need to modify the script a little since Python lz4 has updated its API.
$ python mozlz4a.py -d search.json.mozlz4 search.json $ cat search.json | json_reformat | tee search.json
Step 2: Add the definition of your search engine
Add a new object to the engines array. Here’s the one for GitHub. Modify it as per the configuration of yours.
{
"_name": "GitHub",
"_shortName": "github",
"_loadPath": "[https]github.com/github.xml",
"description": "Search GitHub",
"__searchForm": "https://github.com/search",
"_iconURL": "data:image/x-icon;base64,XXXXX",
"_metaData": {
"loadPathHash": "KMHVysvC2OH4i+7/Ay7hqZvgIBBe8rgxAnMjNkVslos=",
"order": 11,
"alias": "git"
},
"_urls": [
{
"template": "https://github.com/search?q={searchTerms}&ref=opensearch",
"rels": [],
"resultDomain": "github.com",
"params": []
}
],
"queryCharset": "UTF-8",
"_readOnly": false
}
__searchFormcan benullif not needed.- Image to data-URI converter can help you with the
_iconURLfield. - The hash function for
loadPathHashcan be found in Mozilla’s source code. I have copied it here for your convenience. Open a Browser Console in Firefox, paste the following function, callgetVerificationHash(loadPath)and the result is what you need inloadPathHash.
function getVerificationHash(aName) {
let disclaimer = "By modifying this file, I agree that I am doing so " +
"only within $appName itself, using official, user-driven search " +
"engine selection processes, and in a way which does not circumvent " +
"user consent. I acknowledge that any attempt to change this file " +
"from outside of $appName is a malicious act, and will be responded " +
"to accordingly."
let salt = OS.Path.basename(OS.Constants.Path.profileDir) + aName +
disclaimer.replace(/\$appName/g, Services.appinfo.name);
let converter = Cc["@mozilla.org/intl/scriptableunicodeconverter"]
.createInstance(Ci.nsIScriptableUnicodeConverter);
converter.charset = "UTF-8";
// Data is an array of bytes.
let data = converter.convertToByteArray(salt, {});
let hasher = Cc["@mozilla.org/security/hash;1"]
.createInstance(Ci.nsICryptoHash);
hasher.init(hasher.SHA256);
hasher.update(data, data.length);
return hasher.finish(true);
}
Step 3: Replace the original file
Make sure that you’ve closed Firefox entirely and take a backup of the original search.json.mozlz4 file.
$ mv search.json.mozlz4 search.json.mozlz4.bak $ python mozlz4a.py search.json search.json.mozlz4
Then… Done! Yay!
