@ -46,6 +46,12 @@ var forbiddenFirefoxDebPackages = map[string]struct{}{
"util-linux" : { } ,
"util-linux" : { } ,
}
}
type firefoxBundleInstallPlan struct {
TotalPackageCount int
HasFirefoxPackage bool
BaseSystemPackages [ ] string
}
func isFirefoxUsable ( ) bool {
func isFirefoxUsable ( ) bool {
cmd := exec . Command ( "firefox" , "--version" )
cmd := exec . Command ( "firefox" , "--version" )
out , err := cmd . CombinedOutput ( )
out , err := cmd . CombinedOutput ( )
@ -82,10 +88,12 @@ func isExecutableFile(path string) bool {
func installFirefox ( ) error {
func installFirefox ( ) error {
bundlePath := firefoxBundlePath ( )
bundlePath := firefoxBundlePath ( )
if err := validateFirefoxBundle ( bundlePath ) ; err != nil {
plan , err := validateFirefoxBundle ( bundlePath )
if err != nil {
kioskErrorf ( "firefox install refused bundle=%s err=%v" , bundlePath , err )
kioskErrorf ( "firefox install refused bundle=%s err=%v" , bundlePath , err )
return err
return err
}
}
baseSystemPackages := strings . Join ( plan . BaseSystemPackages , " " )
var p struct {
var p struct {
DebPkgPath string ` json:"DebPkgPath" `
DebPkgPath string ` json:"DebPkgPath" `
@ -107,7 +115,7 @@ echo "skip automatic dpkg purge to avoid touching base system packages"
echo ""
echo ""
echo "=== clean previous offline bundle files ==="
echo "=== clean previous offline bundle files ==="
rm - rf / opt / firefox - deb / opt / firefox - deb. tar . gz 2 > / dev / null
rm - rf / opt / firefox - deb / opt / firefox - installable / opt / firefox - deb. tar . gz 2 > / dev / null
echo ""
echo ""
echo "=== start Firefox install ==="
echo "=== start Firefox install ==="
@ -119,20 +127,84 @@ echo "2. extract offline bundle..."
cd / opt && tar - xzvf firefox - deb . tar . gz || { echo "error: extract offline bundle failed" ; exit 1 ; }
cd / opt && tar - xzvf firefox - deb . tar . gz || { echo "error: extract offline bundle failed" ; exit 1 ; }
echo ""
echo ""
echo "3. install Firefox deb packages..."
echo "3. filter Firefox deb packages..."
cd / opt / firefox - deb && sudo dpkg - i * . deb || { echo "error: install Firefox deb packages failed" ; exit 1 ; }
base_system_packages = % s
mkdir - p / opt / firefox - installable
selected_count = 0
skipped_installed_count = 0
selected_missing_base_count = 0
selected_regular_count = 0
firefox_selected = 0
select_deb ( ) {
cp - v "$deb" / opt / firefox - installable /
selected_count = $ ( ( selected_count + 1 ) )
}
for deb in / opt / firefox - deb / * . deb ; do
[ - e "$deb" ] || continue
file = $ ( basename "$deb" )
pkg = $ { file % % _ * }
pkg = $ { pkg % % . deb }
status = $ ( dpkg - query - W - f = ' $ { Status } ' "$pkg" 2 > / dev / null || true )
installed = 0
if [ "$status" = "install ok installed" ] ; then
installed = 1
fi
if [ "$pkg" = "firefox" ] ; then
select_deb
firefox_selected = 1
continue
fi
case " $base_system_packages " in
* " $pkg " * )
if [ "$installed" - eq 1 ] ; then
echo "skip installed base system package: $file"
skipped_installed_count = $ ( ( skipped_installed_count + 1 ) )
continue
fi
echo "select missing base system package: $file"
select_deb
selected_missing_base_count = $ ( ( selected_missing_base_count + 1 ) )
continue
; ;
esac
if [ "$installed" - eq 1 ] ; then
echo "skip installed package: $file"
skipped_installed_count = $ ( ( skipped_installed_count + 1 ) )
continue
fi
select_deb
selected_regular_count = $ ( ( selected_regular_count + 1 ) )
done
echo "selected packages: $selected_count, selected missing base: $selected_missing_base_count, selected regular: $selected_regular_count, skipped installed: $skipped_installed_count"
if [ "$selected_count" - eq 0 ] ; then
echo "error: no packages selected for install"
exit 1
fi
if [ "$firefox_selected" - ne 1 ] ; then
echo "error: Firefox deb package was not selected"
exit 1
fi
echo ""
echo "4. install selected Firefox packages..."
cd / opt / firefox - installable && sudo dpkg - i . / * . deb || { echo "error: install selected Firefox deb packages failed" ; exit 1 ; }
echo ""
echo ""
echo "4. verify Firefox..."
echo " 5 . verify Firefox..."
firefox -- version || { echo "error: Firefox verification failed" ; exit 1 ; }
firefox -- version || { echo "error: Firefox verification failed" ; exit 1 ; }
echo ""
echo ""
echo "=== Firefox install complete ==="
echo "=== Firefox install complete ==="
` , shellQuote ( bundlePath ) ) )
` , shellQuote ( bundlePath ) , shellQuote ( baseSystemPackages ) ))
command . Stdout = os . Stdout
command . Stdout = os . Stdout
command . Stderr = os . Stderr
command . Stderr = os . Stderr
err := command . Run ( )
err = command . Run ( )
if err != nil {
if err != nil {
kioskErrorf ( "firefox install command failed err=%v" , err )
kioskErrorf ( "firefox install command failed err=%v" , err )
return err
return err
@ -173,22 +245,38 @@ func firefoxBundlePath() string {
return filepath . Join ( system . GetPathOfProgram ( ) , g . Config ( ) . Firefox . DebPkgPath , g . Config ( ) . Firefox . DebPkgName )
return filepath . Join ( system . GetPathOfProgram ( ) , g . Config ( ) . Firefox . DebPkgPath , g . Config ( ) . Firefox . DebPkgName )
}
}
func validateFirefoxBundle ( bundlePath string ) error {
func validateFirefoxBundle ( bundlePath string ) ( firefoxBundleInstallPlan , error ) {
packages , err := firefoxBundlePackageNames ( bundlePath )
packages , err := firefoxBundlePackageNames ( bundlePath )
if err != nil {
if err != nil {
return f mt. Errorf ( "read firefox bundle packages: %w" , err )
return f irefoxBundleInstallPlan{ } , f mt. Errorf ( "read firefox bundle packages: %w" , err )
}
}
if len ( packages ) == 0 {
if len ( packages ) == 0 {
return f mt. Errorf ( "firefox bundle has no deb packages" )
return f irefoxBundleInstallPlan{ } , f mt. Errorf ( "firefox bundle has no deb packages" )
}
}
blocked := unsafeFirefoxDeb Packages( packages )
plan := firefoxBundleInstallPlanFrom Packages( packages )
if len ( blocked ) > 0 {
if ! plan . HasFirefoxPackage {
return f mt. Errorf ( "firefox bundle contains blocked base system packages: %s", strings . Join ( blocked , ", " ) )
return f irefoxBundleInstallPlan{ } , f mt. Errorf ( "firefox bundle has no firefox deb package" )
}
}
kioskInfof ( "firefox bundle validation passed bundle=%s packages=%d" , bundlePath , len ( packages ) )
if len ( plan . BaseSystemPackages ) > 0 {
return nil
kioskWarnf ( "firefox bundle contains base system packages; installed ones will be skipped and missing ones may be installed packages=%s" , strings . Join ( plan . BaseSystemPackages , ", " ) )
}
kioskInfof ( "firefox bundle validation passed bundle=%s totalPackages=%d baseSystemPackages=%d hasFirefox=%v" , bundlePath , plan . TotalPackageCount , len ( plan . BaseSystemPackages ) , plan . HasFirefoxPackage )
return plan , nil
}
func firefoxBundleInstallPlanFromPackages ( packages [ ] string ) firefoxBundleInstallPlan {
plan := firefoxBundleInstallPlan {
TotalPackageCount : len ( packages ) ,
BaseSystemPackages : unsafeFirefoxDebPackages ( packages ) ,
}
for _ , name := range packages {
if name == "firefox" {
plan . HasFirefoxPackage = true
}
}
return plan
}
}
func firefoxBundlePackageNames ( bundlePath string ) ( [ ] string , error ) {
func firefoxBundlePackageNames ( bundlePath string ) ( [ ] string , error ) {