Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

fix: use a new strategy for finding the app name in case the title is wrong #25297

Merged
merged 9 commits into from
Jan 10, 2025
1 change: 1 addition & 0 deletions changes/24873-pkg-name
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
- Added a workaround that attempts to get the correct app name for .pkg installers that have default or incorrect app names in their metadata.
jahzielv marked this conversation as resolved.
Show resolved Hide resolved
155 changes: 155 additions & 0 deletions pkg/file/testdata/distribution/distribution-sentinelone.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,155 @@
<?xml version="1.0" encoding="UTF-8"?>
<installer-gui-script authoringTool="Packages" authoringToolVersion="1.2.10" authoringToolBuild="732" minSpecVersion="1.0">
<options rootVolumeOnly="true" customize="never" hostArchitectures="x86_64,arm64"/>
<installation-check script="installation_check()"/>
<volume-check script="volume_check()"/>
<!--+==========================+
| Presentation |
+==========================+-->
<title>DISTRIBUTION_TITLE</title>
<background file="background" uti="public.tiff" scaling="none" alignment="bottomleft" layout-direction="natural"/>
<background-darkAqua file="background" uti="public.tiff" scaling="none" alignment="bottomleft" layout-direction="natural"/>
<!--+==========================+
| Installer |
+==========================+-->
<choices-outline>
<line choice="installer_choice_1"/>
</choices-outline>
<choice id="installer_choice_1" title="SentinelOne" description="">
<pkg-ref id="com.sentinelone.pkg.sentinel-agent"/>
</choice>
<!--+==========================+
| Package References |
+==========================+-->
<pkg-ref id="com.sentinelone.pkg.sentinel-agent" version="24.3.2.7753" auth="Root" installKBytes="151168">#SentinelOne.pkg</pkg-ref>
<!--+==========================+
| JavaScript Scripts |
+==========================+-->
<script>

const __IC_FLAT_DISTRIBUTION__=true;
const IC_OS_DISTRIBUTION_TYPE_ANY=0;
const IC_OS_DISTRIBUTION_TYPE_CLIENT=1;
const IC_DISK_TYPE_DESTINATION=0;
const IC_OS_DISTRIBUTION_TYPE_SERVER=2;
const IC_DISK_TYPE_STARTUP_DISK=1;

function IC_CheckOS(inDiskType,inMustBeInstalled,inMinimumVersion,inMaximumVersion,inDistributionType)
{
var tOSVersion=undefined;

/* Check Version Constraints */

if (inDiskType==IC_DISK_TYPE_DESTINATION)
{
if (my.target.systemVersion!=undefined)
{
tOSVersion=my.target.systemVersion.ProductVersion;
}

/* Check if no OS is installed on the potential target */

if (tOSVersion==undefined)
{
return (inMustBeInstalled==false);
}

if (inMustBeInstalled==false)
{
return false;
}
}
else
{
tOSVersion=system.version.ProductVersion;
}

if (system.compareVersions(tOSVersion,inMinimumVersion)==-1)
return false;

if (inMaximumVersion!=undefined &amp;&amp;
system.compareVersions(tOSVersion,inMaximumVersion)==1)
return false;

/* Check Distribution Type */

if (inDistributionType!=IC_OS_DISTRIBUTION_TYPE_ANY)
{
var tIsServer;

if (system.compareVersions(tOSVersion,'10.8.0')==-1)
{
if (inDiskType==IC_DISK_TYPE_DESTINATION)
{
tIsServer=system.files.fileExistsAtPath(my.target.mountpoint+'/System/Library/CoreServices/ServerVersion.plist');
}
else
{
tIsServer=system.files.fileExistsAtPath('/System/Library/CoreServices/ServerVersion.plist');
}
}
else
{
if (inDiskType==IC_DISK_TYPE_DESTINATION)
{
tIsServer=system.files.fileExistsAtPath(my.target.mountpoint+'/Applications/Server.app');
}
else
{
tIsServer=system.files.fileExistsAtPath('/Applications/Server.app');
}
}

if (inDistributionType==IC_OS_DISTRIBUTION_TYPE_CLIENT &amp;&amp; tIsServer==true)
{
return false;
}

if (inDistributionType==IC_OS_DISTRIBUTION_TYPE_SERVER &amp;&amp; tIsServer==false)
{
return false;
}
}

return true;
}

function IC_CheckMinimumAvailableDiskSpace(inMinimumAvailableSpaceKB)
{
return (my.target.availableKilobytes&gt;=inMinimumAvailableSpaceKB);
}

function installation_check()
{
var tResult;

tResult=IC_CheckOS(IC_DISK_TYPE_STARTUP_DISK,true,'13.0','15.99.99',IC_OS_DISTRIBUTION_TYPE_ANY);

if (tResult==false)
{
my.result.title = system.localizedString('REQUIREMENT_FAILED_MESSAGE_INSTALLATION_CHECK_1');
my.result.message = system.localizedString('REQUIREMENT_FAILED_DESCRIPTION_INSTALLATION_CHECK_1');
my.result.type = 'Fatal';
}

return tResult;
}

function volume_check()
{
var tResult;

tResult=IC_CheckMinimumAvailableDiskSpace(2147483648);

if (tResult==false)
{
my.result.message = system.localizedString('REQUIREMENT_FAILED_MESSAGE_VOLUME_CHECK_2');
my.result.type = 'Fatal';
}

return tResult;
}

</script>
<product version="24.3.2.7753" id="com.sentinelone.sentinel-agent"/>
</installer-gui-script>
29 changes: 25 additions & 4 deletions pkg/file/xar.go
Original file line number Diff line number Diff line change
Expand Up @@ -110,6 +110,7 @@ type distributionXML struct {
Title string `xml:"title"`
Product distributionProduct `xml:"product"`
PkgRefs []distributionPkgRef `xml:"pkg-ref"`
Choices []distributionChoice `xml:"choice"`
}

type packageInfoXML struct {
Expand All @@ -135,6 +136,11 @@ type distributionPkgRef struct {
InstallKBytes string `xml:"installKBytes,attr"`
}

type distributionChoice struct {
PkgRef distributionPkgRef `xml:"pkg-ref"`
Title string `xml:"title,attr"`
}

// distributionBundleVersion represents the bundle-version element
type distributionBundleVersion struct {
Bundles []distributionBundle `xml:"bundle"`
Expand Down Expand Up @@ -270,15 +276,22 @@ func parseDistributionFile(rawXML []byte) (*InstallerMetadata, error) {
BundleIdentifier: identifier,
PackageIDs: packageIDs,
}, nil
}

// Set of package names we know are incorrect. If we see these in the Distribution file we should
// try to get the name some other way.
var knownBadNames = map[string]struct{}{
"DISTRIBUTION_TITLE": {},
"MacFULL": {},
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

MacFULL and SU_TITLE are two other "bad names" that @jmwatts found, as we find more we can add them to this set.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Guessing this fix worked on the other packages @jmwatts found? Or do some of those wind up needing to fall all the way back to bundle ID?

"SU_TITLE": {},
}

// getDistributionInfo gets the name, bundle identifier and version of a PKG distribution file
func getDistributionInfo(d *distributionXML) (name string, identifier string, version string, packageIDs []string) {
var appVersion string

// find the package ids that have an installation size
var packageIDSet = make(map[string]struct{}, 1)
packageIDSet := make(map[string]struct{}, 1)
iansltx marked this conversation as resolved.
Show resolved Hide resolved
for _, pkg := range d.PkgRefs {
if pkg.InstallKBytes != "" && pkg.InstallKBytes != "0" {
var id string
Expand Down Expand Up @@ -368,8 +381,17 @@ out:
if name == "" && d.Title != "" {
name = d.Title
}
if name == "" {

if _, ok := knownBadNames[name]; name == "" || ok {
name = identifier

// Try to find a <choice> tag that matches the bundle ID for this app. It might have the app
// name, so if we find it we can use that.
for _, c := range d.Choices {
if c.PkgRef.ID == identifier && c.Title != "" {
name = c.Title
}
}
jahzielv marked this conversation as resolved.
Show resolved Hide resolved
}

// for the version, try to use the top-level product version, if not,
Expand Down Expand Up @@ -405,12 +427,11 @@ func parsePackageInfoFile(rawXML []byte) (*InstallerMetadata, error) {
BundleIdentifier: identifier,
PackageIDs: packageIDs,
}, nil

}

// getPackageInfo gets the name, bundle identifier and version of a PKG top level PackageInfo file
func getPackageInfo(p *packageInfoXML) (name string, identifier string, version string, packageIDs []string) {
var packageIDSet = make(map[string]struct{}, 1)
packageIDSet := make(map[string]struct{}, 1)
for _, bundle := range p.Bundles {
installPath := bundle.Path
if p.InstallLocation != "" {
Expand Down
49 changes: 35 additions & 14 deletions pkg/file/xar_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -108,8 +108,10 @@ func TestParseRealDistributionFiles(t *testing.T) {
expectedName: "Microsoft Teams.app",
expectedVersion: "24124.1412.2911.3341",
expectedBundleID: "com.microsoft.teams2",
expectedPackageIDs: []string{"com.microsoft.teams2", "com.microsoft.package.Microsoft_AutoUpdate.app",
"com.microsoft.MSTeamsAudioDevice"},
expectedPackageIDs: []string{
"com.microsoft.teams2", "com.microsoft.package.Microsoft_AutoUpdate.app",
"com.microsoft.MSTeamsAudioDevice",
},
},
{
file: "distribution-zoom.xml",
Expand All @@ -123,8 +125,10 @@ func TestParseRealDistributionFiles(t *testing.T) {
expectedName: "Adobe Acrobat Reader.app",
expectedVersion: "24.002.20857",
expectedBundleID: "com.adobe.Reader",
expectedPackageIDs: []string{"com.adobe.acrobat.DC.reader.app.pkg.MUI", "com.adobe.acrobat.DC.reader.appsupport.pkg.MUI",
"com.adobe.acrobat.reader.DC.reader.app.pkg.MUI", "com.adobe.armdc.app.pkg"},
expectedPackageIDs: []string{
"com.adobe.acrobat.DC.reader.app.pkg.MUI", "com.adobe.acrobat.DC.reader.appsupport.pkg.MUI",
"com.adobe.acrobat.reader.DC.reader.app.pkg.MUI", "com.adobe.armdc.app.pkg",
},
},
{
file: "distribution-airtame.xml",
Expand All @@ -138,8 +142,10 @@ func TestParseRealDistributionFiles(t *testing.T) {
expectedName: "Box.app",
expectedVersion: "2.38.173",
expectedBundleID: "com.box.desktop",
expectedPackageIDs: []string{"com.box.desktop.installer.desktop", "com.box.desktop.installer.local.appsupport",
"com.box.desktop.installer.autoupdater", "com.box.desktop.installer.osxfuse"},
expectedPackageIDs: []string{
"com.box.desktop.installer.desktop", "com.box.desktop.installer.local.appsupport",
"com.box.desktop.installer.autoupdater", "com.box.desktop.installer.osxfuse",
},
},
{
file: "distribution-iriunwebcam.xml",
Expand All @@ -155,24 +161,30 @@ func TestParseRealDistributionFiles(t *testing.T) {
expectedName: "Microsoft Excel.app",
expectedVersion: "16.86",
expectedBundleID: "com.microsoft.Excel",
expectedPackageIDs: []string{"com.microsoft.package.Microsoft_Excel.app", "com.microsoft.package.Microsoft_AutoUpdate.app",
"com.microsoft.pkg.licensing"},
expectedPackageIDs: []string{
"com.microsoft.package.Microsoft_Excel.app", "com.microsoft.package.Microsoft_AutoUpdate.app",
"com.microsoft.pkg.licensing",
},
},
{
file: "distribution-microsoftword.xml",
expectedName: "Microsoft Word.app",
expectedVersion: "16.86",
expectedBundleID: "com.microsoft.Word",
expectedPackageIDs: []string{"com.microsoft.package.Microsoft_Word.app", "com.microsoft.package.Microsoft_AutoUpdate.app",
"com.microsoft.pkg.licensing"},
expectedPackageIDs: []string{
"com.microsoft.package.Microsoft_Word.app", "com.microsoft.package.Microsoft_AutoUpdate.app",
"com.microsoft.pkg.licensing",
},
},
{
file: "distribution-miscrosoftpowerpoint.xml",
expectedName: "Microsoft PowerPoint.app",
expectedVersion: "16.86",
expectedBundleID: "com.microsoft.Powerpoint",
expectedPackageIDs: []string{"com.microsoft.package.Microsoft_PowerPoint.app", "com.microsoft.package.Microsoft_AutoUpdate.app",
"com.microsoft.pkg.licensing"},
expectedPackageIDs: []string{
"com.microsoft.package.Microsoft_PowerPoint.app", "com.microsoft.package.Microsoft_AutoUpdate.app",
"com.microsoft.pkg.licensing",
},
},
{
file: "distribution-ringcentral.xml",
Expand All @@ -195,6 +207,13 @@ func TestParseRealDistributionFiles(t *testing.T) {
expectedBundleID: "com.bozo.zeroinstallsize",
expectedPackageIDs: []string{"com.bozo.zeroinstallsize.app"},
},
{
file: "distribution-sentinelone.xml",
expectedName: "SentinelOne",
expectedVersion: "24.3.2.7753",
expectedBundleID: "com.sentinelone.pkg.sentinel-agent",
expectedPackageIDs: []string{"com.sentinelone.pkg.sentinel-agent"},
},
}

for _, tt := range tests {
Expand Down Expand Up @@ -232,8 +251,10 @@ func TestParsePackageInfoFiles(t *testing.T) {
expectedName: "IriunWebcam.app",
expectedVersion: "2.8.10",
expectedBundleID: "com.iriun.macwebcam",
expectedPackageIDs: []string{"com.iriun.macwebcam", "com.iriun.macwebcam.extension4", "com.iriun.macwebcam.extension",
"com.iriun.mic"},
expectedPackageIDs: []string{
"com.iriun.macwebcam", "com.iriun.macwebcam.extension4", "com.iriun.macwebcam.extension",
"com.iriun.mic",
},
},
{
file: "packageInfo-scriptOnly.xml",
Expand Down
Loading