Use a Mac, Windows, or Linux system. (Ubuntu specifically is well tested, but other distros should work)
Install AutoPkg or clone repo and run it using python directly.
Run: autopkg repo-add https://github.com/jgstew/jgstew-recipes.git
These URLs will redirect to the newest Firefox download for each platform. We are going to use these URLs to determine the static download link for the newest version of firefox.
Notice that this URL contains the version number for the latest version of Firefox that we downloaded.
Create an autopkg download recipe Firefox-Mac.download.recipe.yaml
to download the latest Firefox for MacOS using the URL above:
---
Description: Download Firefox for MacOS
Identifier: com.github.macadmins.download.Firefox-Mac
Input:
NAME: Firefox-Mac
MinimumVersion: "2.3"
Process:
- Processor: com.github.jgstew.SharedProcessors/URLDownloaderPython
Arguments:
url: https://download.mozilla.org/?product=firefox-latest-ssl&os=osx&lang=en-US
filename: Firefox.dmg
COMPUTE_HASHES: True
- Processor: EndOfCheckPhase
Run the recipe and see the output. It should download the newest version of firefox.
Add the following to the end of the download recipe to also get the version number:
- Processor: com.github.jgstew.SharedProcessors/TextSearcher
Arguments:
input_string: "%download_url%"
re_pattern: 'releases/(?P<version>\d+(\.\d+)+)/'
Run the recipe again. You should see that firefox does not download again, and this time a version number is shown in the output.
Now compare the download links for macos and windows:
https://download.mozilla.org/?product=firefox-latest-ssl&os=osx&lang=en-US
https://download.mozilla.org/?product=firefox-latest-ssl&os=win64&lang=en-US
The only difference is the macos one uses osx
and the windows one uses win64
. We can restructure the download recipe to make this easier to reuse.
---
Description: Download Firefox for MacOS
Identifier: com.github.macadmins.download.Firefox-Mac
Input:
NAME: Firefox-Mac
os: osx
filename: Firefox.dmg
MinimumVersion: "2.3"
Process:
- Processor: com.github.jgstew.SharedProcessors/URLDownloaderPython
Arguments:
url: https://download.mozilla.org/?product=firefox-latest-ssl&os=%os%&lang=en-US
COMPUTE_HASHES: True
- Processor: EndOfCheckPhase
- Processor: com.github.jgstew.SharedProcessors/TextSearcher
Arguments:
input_string: "%download_url%"
re_pattern: 'releases/(?P<version>\d+(\.\d+)+)/'
Should run this and make sure we get the same output as before.
Now we can create a windows download recipe based upon this one: Firefox-Win.download.recipe.yaml
---
Description: Download Firefox for Win
Identifier: com.github.macadmins.download.Firefox-Win
Input:
NAME: Firefox-Win
os: win64
filename: FirefoxSetup.exe
# https://download.mozilla.org/?product=firefox-latest-ssl&os=osx&lang=en-US
# https://download.mozilla.org/?product=firefox-latest-ssl&os=win64&lang=en-US
MinimumVersion: "2.3"
ParentRecipe: com.github.macadmins.download.Firefox-Mac
Run this and see the different output.
ParentRecipe: com.github.macadmins.Firefox-Mac
means that this recipe will run first, but using the items in the Input
area of our com.github.macadmins.Firefox-Win
recipe.
Then we can do the same, but for Linux: Firefox-Linux.download.recipe.yaml
---
Description: download Firefox for Linux
Identifier: com.github.macadmins.download.Firefox-Linux
Input:
NAME: Firefox-Linux
os: linux64
filename: firefox.tar.xz
# https://download.mozilla.org/?product=firefox-latest-ssl&os=linux64&lang=en-US
# https://download.mozilla.org/?product=firefox-latest-ssl&os=osx&lang=en-US
# https://download.mozilla.org/?product=firefox-latest-ssl&os=win64&lang=en-US
MinimumVersion: "2.3"
ParentRecipe: com.github.macadmins.download.Firefox-Mac
Now that we have a working download recipe for FireFox for MacOS, we need to create a recipe to “package” it for a distribution tool.
For this example, we are going to make a homebrew cask, which is just a ruby file with a specific format.
We are going to start with a working example then turn it into a template so that we can automate the creation of it using AutoPkg.
Here is a working example that installs an outdated version of FireFox: firefox.example.rb
# https://github.com/Homebrew/homebrew-cask/blob/master/Casks/f/firefox.rb
cask "firefox" do
version "127.0.2"
language "en", default: true do
sha256 "af516f0222361a311e83de8ca9a27a99653b2c0a00a6653e25ab59046a44d128"
"en-US"
end
url "https://download-installer.cdn.mozilla.net/pub/firefox/releases/#{version}/mac/#{language}/Firefox%20#{version}.dmg",
verified: "download-installer.cdn.mozilla.net/pub/firefox/releases/"
name "Mozilla Firefox"
desc "Web browser"
homepage "https://www.mozilla.org/firefox/"
livecheck do
url "https://download.mozilla.org/?product=firefox-latest-ssl&os=osx"
strategy :header_match
end
auto_updates true
conflicts_with cask: [
"firefox@beta",
"firefox@cn",
"firefox@esr",
]
depends_on macos: ">= :catalina"
app "Firefox.app"
# shim script (https://github.com/Homebrew/homebrew-cask/issues/18809)
shimscript = "#{staged_path}/firefox.wrapper.sh"
binary shimscript, target: "firefox"
preflight do
File.write shimscript, <<~EOS
#!/bin/bash
exec '#{appdir}/Firefox.app/Contents/MacOS/firefox' "$@"
EOS
end
uninstall quit: "org.mozilla.firefox"
zap trash: [
"/Library/Logs/DiagnosticReports/firefox_*",
"~/Library/Application Support/com.apple.sharedfilelist/com.apple.LSSharedFileList.ApplicationRecentDocuments/org.mozilla.firefox.sfl*",
"~/Library/Application Support/CrashReporter/firefox_*",
"~/Library/Application Support/Firefox",
"~/Library/Caches/Firefox",
"~/Library/Caches/Mozilla/updates/Applications/Firefox",
"~/Library/Caches/org.mozilla.crashreporter",
"~/Library/Caches/org.mozilla.firefox",
"~/Library/Preferences/org.mozilla.crashreporter.plist",
"~/Library/Preferences/org.mozilla.firefox.plist",
"~/Library/Saved Application State/org.mozilla.firefox.savedState",
"~/Library/WebKit/org.mozilla.firefox",
],
rmdir: [
"~/Library/Application Support/Mozilla", # May also contain non-Firefox data
"~/Library/Caches/Mozilla",
"~/Library/Caches/Mozilla/updates",
"~/Library/Caches/Mozilla/updates/Applications",
]
end
We can test this existing example to make sure it works using:
brew install --cask --verbose firefox.rb
We can turn this into a template by making a copy, renaming it to firefox.template.rb
and changing the following:
version "127.0.2"
to version ""
sha256 "af516f0222361a311e83de8ca9a27a99653b2c0a00a6653e25ab59046a44d128"
to sha256 ""
Now make a cask recipe that will use this template: Firefox-Mac.cask.recipe.yaml
---
Description: Creates an homebrew cask for the latest version of Firefox
Identifier: com.github.macadmins.cask.Firefox-Mac
Input:
NAME: "Firefox"
OS: osx
filename: Firefox.dmg
MinimumVersion: "2.3"
ParentRecipe: com.github.macadmins.download.Firefox-Mac
Process:
# this is not actually BigFix specific, just sets up some defaults in the template dictionary:
- Processor: com.github.jgstew.SharedProcessors/BigFixSetupTemplateDictionary
# this generates the homebrew cask from the template
- Processor: com.github.jgstew.SharedProcessors/ContentFromTemplate
Arguments:
template_file_path: "%RECIPE_DIR%/firefox.template.rb"
content_file_pathname: "%RECIPE_CACHE_DIR%/firefox.rb"
Run this recipe, and it will generate the firefox homebrew cask.
autopkg run -vv Firefox/Firefox-Mac.cask.recipe.yaml
The generated item should be in a location like: (varies by OS)
/Users/_USER_/Library/AutoPkg/Cache/com.github.macadmins.cask.Firefox-Mac/firefox.rb
Can test this generated cask on a MacOS test machine:
brew install --cask /Users/_USER_/Library/AutoPkg/Cache/com.github.macadmins.cask.Firefox-Mac/firefox.rb
From here, AutoPkg can import this into your preferred management tool, you can test it, and run on a target systems.
Now a similar example for Linux, but this time using a bash script to install firefox.
Create a bash script to install FireFox on Linux, based upon the Mozilla documentation: firefox-install-linux.example.sh
#!/bin/bash
# URL of the file to download
url="https://download-installer.cdn.mozilla.net/pub/firefox/releases/137.0/linux-x86_64/en-US/firefox-137.0.tar.xz"
# Expected SHA-256 hash of the file
expected_sha256="4d2d0a64a11f8aab7a1be583e1e4cddfaf2671967212b369a87489f3c11c3ac9"
# Temporary file to store downloaded content
download_file_path=/tmp/firefox.tar.xz
# install prereqs if missing (docker)
if command -v apt &> /dev/null; then
apt install -y curl bzip2 xz-utils
fi
# Download the file using curl
curl -sSL "$url" -o "$download_file_path"
# Calculate the SHA-256 hash of the downloaded file
actual_sha256=$(sha256sum "$download_file_path" | awk '{print $1}')
# Compare the calculated hash with the expected hash
if [ "$actual_sha256" == "$expected_sha256" ]; then
echo "File downloaded successfully and hash matched: $actual_sha256"
echo "Installing"
# https://support.mozilla.org/en-US/kb/install-firefox-linux
cd /tmp
# tweak to handle .tar.xz files
tar xJf $download_file_path
rm -rf /opt/firefox
mv firefox /opt
rm -f /usr/local/bin/firefox
ln -s /opt/firefox/firefox /usr/local/bin/firefox
mkdir -p /usr/local/share/applications
cat <<ENDOFTOKEN > /usr/local/share/applications/firefox.desktop
[Desktop Entry]
Version=1.0
Name=Firefox Web Browser
Comment=Browse the World Wide Web
GenericName=Web Browser
Keywords=Internet;WWW;Browser;Web;Explorer
Exec=firefox %u
Terminal=false
X-MultipleArgs=false
Type=Application
Icon=/opt/firefox/browser/chrome/icons/default/default128.png
Categories=GNOME;GTK;Network;WebBrowser;
MimeType=text/html;text/xml;application/xhtml+xml;application/xml;application/rss+xml;application/rdf+xml;image/gif;image/jpeg;image/png;x-scheme-handler/http;x-scheme-handler/https;x-scheme-handler/ftp;x-scheme-handler/chrome;video/webm;application/x-xpinstall;
StartupNotify=true
ENDOFTOKEN
echo "FireFox installed!"
else
echo "Hash verification failed! Expected: $expected_sha256, Actual: $actual_sha256"
fi
We can turn this into a template by making a copy, renaming it to firefox-install-linux.template.sh
and changing the following:
url="https://download-installer.cdn.mozilla.net/pub/firefox/releases/137.0/linux-x86_64/en-US/firefox-137.0.tar.xz"
to url=""
expected_sha256="4d2d0a64a11f8aab7a1be583e1e4cddfaf2671967212b369a87489f3c11c3ac9"
to expected_sha256=""
Now make an installscript recipe that will use this template:
---
Description: Creates an install script for the latest version of Firefox
Identifier: com.github.macadmins.installscript.Firefox-Linux
Input:
NAME: Firefox-Linux
OS: linux64
filename: firefox.tar.xz
MinimumVersion: "2.3"
ParentRecipe: com.github.macadmins.download.Firefox-Linux
Process:
# this is not actually BigFix specific, just sets up some defaults in the template dictionary:
- Processor: com.github.jgstew.SharedProcessors/BigFixSetupTemplateDictionary
# this generates the install script from the template
- Processor: com.github.jgstew.SharedProcessors/ContentFromTemplate
Arguments:
template_file_path: "%RECIPE_DIR%/firefox-install-linux.template.sh"
content_file_pathname: "%RECIPE_CACHE_DIR%/install-firefox-linux.sh"
Run this recipe, and it will generate the firefox install script.
autopkg run -vv Firefox/Firefox-Linux.installscript.recipe.yaml
The generated item should be in a location like: (varies by OS)
/Users/_USER_/Library/AutoPkg/Cache/com.github.macadmins.installscript.Firefox-Linux/install-firefox-linux.sh
Can then test this script on a linux test machine: (or docker container)
bash install-firefox-linux.sh
From here, AutoPkg can import this into your preferred management tool, you can test it, and run on a target systems.
Now that we have a working download recipe for FireFox for Windows, we need to create a recipe to “package” it for a distribution tool.
For this example, we are going to make a chocolatey package, which is really just a zip file with specific files in it.
We are going to start with a working example then turn it into a template so that we can automate the creation of it using AutoPkg.
In this case we are going to bundle the Firefox download into the chocolatey package itself, so then this can be deployed to systems that do not have an internet connection.
Here is a working example that installs an outdated version of FireFox:
$ErrorActionPreference = 'Stop'
$toolsDir = "$(Split-Path -Parent $MyInvocation.MyCommand.Definition)"
$file = Join-Path $toolsDir 'FirefoxSetup.exe'
$packageArgs = @{
packageName = 'Firefox'
fileType = 'exe'
silentArgs = '/S'
file = $file
}
Install-ChocolateyInstallPackage @packageArgs
Turn this into a template by changing 'FirefoxSetup.exe'
into ''
Rename it to Firefox-Win.ChocolateyTemplate.chocolateyInstall.ps1
<?xml version="1.0" encoding="utf-8"?>
<package xmlns="http://schemas.microsoft.com/packaging/2010/07/nuspec.xsd">
<metadata>
<id>Firefox</id>
<version>127.0.2</version>
<title>Firefox</title>
<authors>Mozilla</authors>
<requireLicenseAcceptance>false</requireLicenseAcceptance>
<description>Firefox web browser.</description>
</metadata>
</package>
Turn this into a template by changing <version>127.0.2</version>
into <version></version>
Rename it to Firefox-Win.ChocolateyTemplate.Firefox.nuspec
Create a recipe to create the chocolatey package from the templates:
---
Description: Creates an choco package for the latest version of Firefox
Identifier: com.github.macadmins.ChocolateyTemplate.Firefox-Win64
Input:
NAME: "Firefox"
OS: win64
filename: FirefoxSetup.exe
# https://download.mozilla.org/?product=firefox-latest-ssl&os=linux64&lang=en-US
# https://download.mozilla.org/?product=firefox-msi-latest-ssl&os=win64&lang=en-US
MinimumVersion: "2.3"
ParentRecipe: com.github.macadmins.download.Firefox-Win
Process:
# this is not actually BigFix specific, just sets up some defaults in the template dictionary:
- Processor: com.github.jgstew.SharedProcessors/BigFixSetupTemplateDictionary
# create missing folders:
- Processor: com.github.jgstew.SharedProcessors/FileTouch
Arguments:
pathname: "%RECIPE_CACHE_DIR%/tmp/tools/chocolateyInstall.ps1"
touch_create_folders: True
# create Firefox.nuspec from template
- Processor: com.github.jgstew.SharedProcessors/ContentFromTemplate
Arguments:
template_file_path: "%RECIPE_DIR%/Firefox-Win.ChocolateyTemplate.Firefox.nuspec"
content_file_pathname: "%RECIPE_CACHE_DIR%/tmp/Firefox.nuspec"
# create chocolateyInstall.ps1 from template
# https://docs.chocolatey.org/en-us/create/create-packages/
# https://docs.chocolatey.org/en-us/create/functions/install-chocolateypackage/
- Processor: com.github.jgstew.SharedProcessors/ContentFromTemplate
Arguments:
template_file_path: "%RECIPE_DIR%/Firefox-Win.ChocolateyTemplate.chocolateyInstall.ps1"
content_file_pathname: "%RECIPE_CACHE_DIR%/tmp/tools/chocolateyInstall.ps1"
# copy FirefoxSetup.exe into tmp directory for creation of nupkg
- Processor: com.github.jgstew.SharedProcessors/FileCopyNewest
Arguments:
file_path_first: "%RECIPE_CACHE_DIR%/downloads/FirefoxSetup.exe"
file_path_second: "%RECIPE_CACHE_DIR%/tmp/tools/FirefoxSetup.exe"
# create zip file Firefox.nupkg
- Processor: com.github.jgstew.SharedProcessors/SevenZip
Arguments:
sevenzip_args: ["a", "-tzip", "../firefox.nupkg", "*"]
# need to change the relative directory to NOT include the directory name
relative_directory: tmp
Run this recipe, and it will generate the firefox chocolatey package.
autopkg run -vv Firefox/Firefox-Win.ChocolateyTemplate.recipe.yaml
The generated item should be in a location like: (varies by OS)
/Users/_User_/Library/AutoPkg/Cache/com.github.macadmins.ChocolateyTemplate.Firefox-Win64/firefox.nupkg
Can test this generated chocolatey package on a Windows test machine:
choco install firefox -s "$env:USERPROFILE\Library\AutoPkg\Cache\com.github.macadmins.ChocolateyTemplate.Firefox-Win64\" --pre --no-progress --yes --force --verbose
From here, AutoPkg can import this into your preferred management tool, you can test it, and run on a target systems.
Because the process to create Chocolatey packages doesn’t vary much between different software titles, you can then turn this FireFox recipe into one that uses the Input variables and is easier to reuse.
Now that we have a working download recipe for FireFox for Windows, we need to create a recipe to “package” it for a distribution tool.
For this example, we are going to make a BigFix Install Task, which is really just an XML file.
We are going to start with a working example then turn it into a template so that we can automate the creation of it using AutoPkg.
Here is a working example that installs an outdated version of FireFox:
<?xml version="1.0" encoding="UTF-8"?>
<BES xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="BES.xsd">
<Task>
<Title>Install: Mozilla Firefox v127.0.2 - Windows</Title>
<Description><![CDATA[
This task will download and install "Mozilla Firefox v127.0.2" package onto selected endpoints.
]]></Description>
<Relevance>windows of operating system</Relevance>
<Relevance><![CDATA[not exists keys whose(value "DisplayName" of it as string starts with "Mozilla Firefox") of keys "HKLM\Software\Microsoft\Windows\CurrentVersion\Uninstall" of (x32 registries; x64 registries)]]></Relevance>
<Category></Category>
<DownloadSize>64728328</DownloadSize>
<Source>Mozilla</Source>
<SourceID></SourceID>
<SourceReleaseDate>2024-06-25</SourceReleaseDate>
<SourceSeverity></SourceSeverity>
<CVENames></CVENames>
<SANSID></SANSID>
<MIMEField>
<Name>x-fixlet-modification-time</Name>
<Value>Sun, 07 Jul 2024 17:49:09 +0000</Value>
</MIMEField>
<Domain>BESC</Domain>
<DefaultAction ID="Action1">
<Description>
<PreLink>Click </PreLink>
<Link>here</Link>
<PostLink> to deploy Mozilla Firefox v127.0.2.</PostLink>
</Description>
<ActionScript MIMEType="application/x-Fixlet-Windows-Shell"><![CDATA[
// Download:
prefetch FirefoxSetup.exe sha1:97d16ec0c749ede9244446507ed4ae53f4c7a873 size:64728328 https://download.mozilla.org/?product=firefox-latest-ssl&os=win64&lang=en-US sha256:aa20d3d8f755f13db6091665439f310a850a86cd06d326c8db449ebacfa50051
// Install:
wait __Download\FirefoxSetup.exe /S
// End]]></ActionScript>
<SuccessCriteria Option="OriginalRelevance"></SuccessCriteria>
</DefaultAction>
</Task>
</BES>
Turn this into a template by changing:
<DownloadSize>64728328</DownloadSize>
into <DownloadSize></DownloadSize>
<SourceReleaseDate>2024-06-25</SourceReleaseDate>
into <SourceReleaseDate></SourceReleaseDate>
<Value>Sun, 07 Jul 2024 17:49:09 +0000</Value>
into <Value></Value>
the line prefetch FirefoxSetup.exe sha1:
… into ``
Search and replace 127.0.2
to ``
Rename it to Firefox-Win.bigfix.install.template.bes
Create a recipe to create the BigFix install task from the templates:
---
Description: Creates a bigfix install fixlet for the latest version of Firefox
Identifier: com.github.macadmins.bigfix.Firefox-Win
Input:
NAME: "Firefox"
DisplayName: "Mozilla Firefox"
OS: win64
filename: FirefoxSetup.exe
# https://download.mozilla.org/?product=firefox-latest-ssl&os=linux64&lang=en-US
# https://download.mozilla.org/?product=firefox-msi-latest-ssl&os=win64&lang=en-US
MinimumVersion: "2.3"
ParentRecipe: com.github.macadmins.download.Firefox-Win
Process:
- Processor: com.github.jgstew.SharedProcessors/BigFixPrefetchItem
Arguments:
prefetch_url: "%download_url%"
- Processor: com.github.jgstew.SharedProcessors/BigFixSetupTemplateDictionary
- Processor: com.github.jgstew.SharedProcessors/TemplateDictionaryAppendInput
- Processor: com.github.jgstew.SharedProcessors/ContentFromTemplate
Arguments:
# use UNIX style paths so this works on Windows and non-Windows:
template_file_path: "%RECIPE_DIR%/Firefox-Win.bigfix.install.template.bes"
content_file_pathname: "%RECIPE_CACHE_DIR%/%NAME%-Install.bes"
# - Processor: com.github.jgstew.SharedProcessors/BESImport
# - Processor: com.github.jgstew.SharedProcessors/BigFixActioner