Skip to content

Commit d22d378

Browse files
Merge pull request #150 from root3nl/development
v2.5.1
2 parents abe1d66 + 4c5e730 commit d22d378

12 files changed

Lines changed: 58 additions & 47 deletions

File tree

Jamf Pro Custom Schema/Jamf Pro Custom Schema.json

Lines changed: 0 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -105,21 +105,6 @@
105105
}
106106
]
107107
},
108-
"HideMajorUpdates": {
109-
"title": "Hide major macOS updates",
110-
"description": "Ignore macOS major updates. This will prevent the menu bar icon and the macOS version info item from showing an available major update. Only applicable to macOS 12.3 and higher",
111-
"type": "boolean",
112-
"options": {
113-
"enum_titles": ["Hide", "Show"],
114-
"infoText": "Key name: HideMajorUpdates"
115-
},
116-
"links": [
117-
{
118-
"rel": "Documentation",
119-
"href": "https://github.com/root3nl/SupportApp"
120-
}
121-
]
122-
},
123108
"UpdateText": {
124109
"title": "Update Text",
125110
"description": "Optional text to shown in the macOS Managed Updates popover to tell users about the updates",

README.md

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -199,6 +199,9 @@ The popover allows the user to open System Settings and install the update or up
199199

200200
<img src="/Screenshots/software_update_integration.png" width="500">
201201

202+
> **Note**
203+
> When a deferral is set using the preference key `forceDelayedMajorSoftwareUpdates` in the domain `com.apple.applicationaccess`, major macOS updates will automatically be hidden indefinitely until the key is removed or set to `false`. The amount of days configured for the deferral are ignored. Due to limitations and complexity, it is not supported to automatically show the macOS major update once the deferral days are passed. This behaviour replaces the `HideMajorUpdates` key, previously available in version 2.5 and earlier. More info here: https://developer.apple.com/documentation/devicemanagement/restrictions
204+
202205
## Configuration
203206
The configuration of the Support app is optimized for use with your MDM solution. The easiest way to configure the app is using a Configuration Profile so you can use whatever MDM solution you like, as long as it supports custom Configuration Profiles.
204207

@@ -219,7 +222,6 @@ All general settings
219222
| StatusBarIcon | String | Root3 Logo | Remote URL or path to the status bar icon shown in the menu bar. Recommended: PNG, 16x16 points. Icons larger than 22 points will automatically be resized to 16 points. A subfolder in `/Library/Application Support/` is the recommended location due to sandboxing | `/Library/Application Support/Your Company/statusbaricon.png` or `https://domain.tld/url_to_image.png` |
220223
| StatusBarIconSFSymbol | String | Root3 Logo | Custom status bar icon using an SF Symbol. Ignored when StatusBarIcon is also set | “lifepreserver” |
221224
| StatusBarIconNotifierEnabled | Boolean | false | Shows a small notification badge in the Status Bar Icon when an info items triggers a warning or notification | true |
222-
| HideMajorUpdates | Boolean | false | Ignore macOS major updates. This will prevent the menu bar icon and the macOS version info item from showing an available major update. Only applicable to macOS 12.3 and higher | true |
223225
| UpdateText | String | - | The text shown below the software update details popover | "Your organization requires you to update as soon as possible. [More info...](https://URL_TO_YOUR_UPDATE_POLICY)" |
224226
| CustomColor | String | macOS Accent Color | Custom color for all symbols. Leave empty to use macOS Accent Color. We recommend not to use a very light color as text may become hard to read | HEX color in RGB format like "#8cc63f" |
225227
| CustomColorDarkMode | String | macOS Accent Color | Custom color for all symbols in Dark Mode. Leave empty to use macOS Accent Color or CustomColor if specified. We recommend not to use a very dark color as text may become hard to read | HEX color in RGB format like "#8cc63f" |

pkgbuild/scripts/postinstall

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -26,14 +26,24 @@ install_location="/Applications/Support.app"
2626
username=$(scutil <<< "show State:/Users/ConsoleUser" | awk '/Name :/ && ! /loginwindow/ { print $3 }')
2727

2828
# Remove "Downloaded from Internet" warning
29-
xattr -d -r com.apple.quarantine "${install_location}"
29+
# xattr -d -r com.apple.quarantine "${install_location}"
3030

3131
# Load Requirements
3232
autoload is-at-least
3333

3434
# macOS Version
3535
os_version=$(sw_vers -productVersion)
3636

37+
# ------------------ Gatekeeper scan ------------------
38+
39+
# Perform a Gatekeeper scan. This is useful for pre-warming the cache so users
40+
# do not see the 'Verifying...' dialog on first launch of an application.
41+
if is-at-least 14.0 ${os_version}; then
42+
gktool scan "${install_location}"
43+
fi
44+
45+
# ------------------ LaunchAgent ------------------
46+
3747
# Open the app so the legacy LaunchAgent properly displays the app name and icon
3848
# in System Settings > General > Login Items
3949
# Tested and does only work when a user is logged in during the installation

src/Support.xcodeproj/project.pbxproj

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -569,7 +569,7 @@
569569
"@executable_path/../Frameworks",
570570
);
571571
MACOSX_DEPLOYMENT_TARGET = 11.0;
572-
MARKETING_VERSION = 2.5;
572+
MARKETING_VERSION = 2.5.1;
573573
PRODUCT_BUNDLE_IDENTIFIER = nl.root3.support;
574574
PRODUCT_NAME = "$(TARGET_NAME)";
575575
PROVISIONING_PROFILE_SPECIFIER = "";
@@ -598,7 +598,7 @@
598598
"@executable_path/../Frameworks",
599599
);
600600
MACOSX_DEPLOYMENT_TARGET = 11.0;
601-
MARKETING_VERSION = 2.5;
601+
MARKETING_VERSION = 2.5.1;
602602
PRODUCT_BUNDLE_IDENTIFIER = nl.root3.support;
603603
PRODUCT_NAME = "$(TARGET_NAME)";
604604
PROVISIONING_PROFILE_SPECIFIER = "";

src/Support/AppDelegate.swift

Lines changed: 11 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,9 @@ class AppDelegate: NSObject, NSApplicationDelegate {
3434
// Make UserDefaults easy to use with suite "com.apple.SoftwareUpdate"
3535
let ASUdefaults = UserDefaults(suiteName: "com.apple.SoftwareUpdate")
3636

37+
// Make UserDefaults easy to use with suite "com.apple.applicationaccess"
38+
let restrictionsDefaults = UserDefaults(suiteName: "com.apple.applicationaccess")
39+
3740
// Make properties and preferences available
3841
var computerinfo = ComputerInfo()
3942
var userinfo = UserInfo()
@@ -108,6 +111,7 @@ class AppDelegate: NSObject, NSApplicationDelegate {
108111
defaults.addObserver(self, forKeyPath: "StorageLimit", options: .new, context: nil)
109112
defaults.addObserver(self, forKeyPath: "PasswordExpiryLimit", options: .new, context: nil)
110113
defaults.addObserver(self, forKeyPath: "OpenAtLogin", options: .new, context: nil)
114+
restrictionsDefaults?.addObserver(self, forKeyPath: "forceDelayedMajorSoftwareUpdates", options: .new, context: nil)
111115
ASUdefaults?.addObserver(self, forKeyPath: "LastUpdatesAvailable", options: .new, context: nil)
112116
ASUdefaults?.addObserver(self, forKeyPath: "RecommendedUpdates", options: .new, context: nil)
113117

@@ -289,22 +293,18 @@ class AppDelegate: NSObject, NSApplicationDelegate {
289293
preferences.infoItemSix
290294
]
291295

292-
// Number of available software updates
293-
var updatesAvailable = computerinfo.updatesAvailable
294-
295296
// If configured, ignore major macOS version updates
296-
if preferences.hideMajorUpdates {
297-
logger.debug("HideMajorUpdates is enabled, hiding \(self.computerinfo.majorVersionUpdates) major macOS updates")
298-
updatesAvailable -= computerinfo.majorVersionUpdates
297+
if computerinfo.forceDelayedMajorSoftwareUpdates {
298+
logger.debug("forceDelayedMajorSoftwareUpdates is enabled, hiding \(self.computerinfo.majorVersionUpdates) major macOS updates")
299299
}
300300

301301
// Show notification badge in menu bar icon when info item when needed
302-
if (updatesAvailable == 0 || !infoItemsEnabled.contains("MacOSVersion")) && ((computerinfo.uptimeLimitReached && infoItemsEnabled.contains("Uptime")) || (computerinfo.selfSignedIP && infoItemsEnabled.contains("Network")) || (userinfo.passwordExpiryLimitReached && infoItemsEnabled.contains("Password")) || (computerinfo.storageLimitReached && infoItemsEnabled.contains("Storage")) || (preferences.extensionAlertA && infoItemsEnabled.contains("ExtensionA")) || (preferences.extensionAlertB && infoItemsEnabled.contains("ExtensionB"))) && defaults.bool(forKey: "StatusBarIconNotifierEnabled") {
302+
if (computerinfo.updatesAvailableToShow == 0 || !infoItemsEnabled.contains("MacOSVersion")) && ((computerinfo.uptimeLimitReached && infoItemsEnabled.contains("Uptime")) || (computerinfo.selfSignedIP && infoItemsEnabled.contains("Network")) || (userinfo.passwordExpiryLimitReached && infoItemsEnabled.contains("Password")) || (computerinfo.storageLimitReached && infoItemsEnabled.contains("Storage")) || (preferences.extensionAlertA && infoItemsEnabled.contains("ExtensionA")) || (preferences.extensionAlertB && infoItemsEnabled.contains("ExtensionB"))) && defaults.bool(forKey: "StatusBarIconNotifierEnabled") {
303303

304304
// Create orange notification badge
305305
orangeBadge.isHidden = false
306306

307-
} else if (updatesAvailable > 0 && infoItemsEnabled.contains("MacOSVersion")) && defaults.bool(forKey: "StatusBarIconNotifierEnabled") {
307+
} else if (computerinfo.updatesAvailableToShow > 0 && infoItemsEnabled.contains("MacOSVersion")) && defaults.bool(forKey: "StatusBarIconNotifierEnabled") {
308308

309309
// Create red notification badge
310310
redBadge.isHidden = false
@@ -408,6 +408,9 @@ class AppDelegate: NSObject, NSApplicationDelegate {
408408
case "OpenAtLogin":
409409
logger.debug("\(keyPath! as NSObject) changed to \(self.defaults.bool(forKey: "OpenAtLogin"), privacy: .public)")
410410
self.configureLaunchAgent()
411+
case "forceDelayedMajorSoftwareUpdates":
412+
logger.debug("\(keyPath! as NSObject) changed to \(self.restrictionsDefaults!.bool(forKey: "forceDelayedMajorSoftwareUpdates"), privacy: .public)")
413+
self.computerinfo.getRecommendedUpdates()
411414
case "ExtensionAlertA":
412415
logger.debug("\(keyPath! as NSObject) changed to \(self.preferences.extensionAlertA, privacy: .public)")
413416
case "ExtensionAlertB":

src/Support/ComputerInfo.swift

Lines changed: 25 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -71,6 +71,18 @@ class ComputerInfo: ObservableObject {
7171
// Number of major macOS Software Updates
7272
@Published var majorVersionUpdates: Int = 0
7373

74+
// Calculate number of updates to show, excluding any major upgrades if hidden using 'forceDelayedMajorSoftwareUpdates' in a restrictions profile
75+
var updatesAvailableToShow: Int {
76+
if forceDelayedMajorSoftwareUpdates {
77+
return updatesAvailable - majorVersionUpdates
78+
} else {
79+
return updatesAvailable
80+
}
81+
}
82+
83+
// Get if major OS updates are deferred using a restrictions profile
84+
@AppStorage("forceDelayedMajorSoftwareUpdates", store: UserDefaults(suiteName: "com.apple.applicationaccess")) var forceDelayedMajorSoftwareUpdates: Bool = false
85+
7486
// Computer name
7587
@Published var hostname = String()
7688

@@ -325,7 +337,7 @@ class ComputerInfo: ObservableObject {
325337

326338
// Command to get c
327339
let computerNameCommand = """
328-
ioreg -l -c IOPlatformDevice | grep -e "product-name" | cut -d'"' -f 4
340+
ioreg -c IOPlatformDevice | grep -e "product-name" | cut -d'"' -f 4
329341
"""
330342

331343
// Move command to background thread
@@ -652,6 +664,12 @@ class ComputerInfo: ObservableObject {
652664
// Return when decoded RecommendedUpdates array is empty
653665
guard !decodedItems.isEmpty else {
654666
self.logger.debug("RecommendedUpdates is empty...")
667+
668+
// Remove all updates from UI
669+
DispatchQueue.main.async {
670+
self.recommendedUpdates = []
671+
}
672+
655673
return
656674
}
657675

@@ -661,16 +679,20 @@ class ComputerInfo: ObservableObject {
661679
self.logger.debug("Updates found: \(decodedItems.count)")
662680

663681
// Loop through all available updates and decrease number of updates when available macOS version is higher than current major version
664-
for item in decodedItems {
682+
for (index, item) in decodedItems.enumerated() {
665683
// Filter updates with "macOS" in Display Name
666684
if item.displayName.contains("macOS") {
667685
// Get digits from Display Version separated by a dot to get the major version
668686
if let version = item.displayVersion?.components(separatedBy: ".")[0] {
669687
self.logger.debug("macOS update found: \(item.displayName, privacy: .public)")
670688
// Convert to integer and compare with current major OS version. If higher, increase number of major OS updates
671689
if Int(version) ?? 0 > self.systemVersionMajor {
672-
self.logger.debug("macOS version \(version, privacy: .public) is higher than the current macOS version (\(self.systemVersionMajor)), update will be hidden when DeferMajorVersions is enabled")
690+
self.logger.debug("macOS version \(version, privacy: .public) is higher than the current macOS version (\(self.systemVersionMajor)), update will be hidden when forceDelayedMajorSoftwareUpdates is enabled")
673691
majorVersionUpdatesTemp += 1
692+
// Remove update item from array if forceDelayedMajorSoftwareUpdates is enabled
693+
if self.forceDelayedMajorSoftwareUpdates && decodedItems.indices.contains(index) {
694+
decodedItems.remove(at: index)
695+
}
674696
}
675697
} else {
676698
self.logger.error("Error getting macOS version from \(item.displayName, privacy: .public)")

src/Support/Extensions.swift

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -161,7 +161,7 @@ extension String {
161161
("$LocalMacosVersionName", computerInfo.macOSVersionName),
162162
("$LocalSerialNumber", computerInfo.deviceSerialNumber),
163163
("$LocalIpAddress", computerInfo.ipAddress),
164-
("$LocalUpdatesAvailable", "\(computerInfo.updatesAvailable)"),
164+
("$LocalUpdatesAvailable", "\(computerInfo.updatesAvailableToShow)"),
165165
("\\n", "\n")
166166
]
167167

src/Support/Info.plist

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,7 @@
1919
<key>CFBundleShortVersionString</key>
2020
<string>$(MARKETING_VERSION)</string>
2121
<key>CFBundleVersion</key>
22-
<string>1690815745</string>
22+
<string>1695998775</string>
2323
<key>LSApplicationCategoryType</key>
2424
<string>public.app-category.utilities</string>
2525
<key>LSMinimumSystemVersion</key>

src/Support/Preferences.swift

Lines changed: 0 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -41,9 +41,6 @@ class Preferences: ObservableObject {
4141
// Automatically register modern LaunchAgent on macOS 13 and higher
4242
@AppStorage("OpenAtLogin") var openAtLogin: Bool = false
4343

44-
// Hide major updates for macOS
45-
@AppStorage("HideMajorUpdates") var hideMajorUpdates: Bool = false
46-
4744
// Optional text to show in the Managed Updates view
4845
@AppStorage("UpdateText") var updateText: String = ""
4946

src/Support/Support.entitlements

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@
88
<true/>
99
<key>com.apple.security.temporary-exception.shared-preference.read-only</key>
1010
<array>
11+
<string>com.apple.applicationaccess</string>
1112
<string>com.trusourcelabs.NoMAD</string>
1213
<string>com.apple.SoftwareUpdate</string>
1314
<string>com.jamf.connect.state</string>

0 commit comments

Comments
 (0)