Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 2 additions & 1 deletion CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,8 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
### Changed
- Update print and os_log calls to the modern OSLog class calls for updated logging. ([Issue #112](https://github.com/jamf/PPPC-Utility/issues/112)) [@SkylerGodfrey](https://github.com/SkylerGodfrey)
- Now using [Haversack](https://github.com/jamf/Haversack) for simplified access to the keychain ([Issue #124](https://github.com/jamf/PPPC-Utility/issues/124)) [@macblazer](https://github.com/macblazer).
- PPPC Utility now requires macOS 11+ to run. It can still produce profiles usable on older versions of macOS.
- PPPC Utility now requires macOS 13+ to run. It can still produce profiles usable on older versions of macOS.
- Removed Big Sur compatibility toggle and legacy `Allowed` key support. The `Authorization` key is now always used.

## [1.5.0] - 2022-10-04

Expand Down
8 changes: 2 additions & 6 deletions PPPC Utility.xcodeproj/project.pbxproj
Original file line number Diff line number Diff line change
Expand Up @@ -59,7 +59,6 @@
C0EE9A7D28639BF800738B6B /* TestTCCProfileForJamfProAPI.txt in Resources */ = {isa = PBXBuildFile; fileRef = C0EE9A7C28639BF800738B6B /* TestTCCProfileForJamfProAPI.txt */; };
C0EE9A7F2863BDE300738B6B /* JamfProAPITypes.swift in Sources */ = {isa = PBXBuildFile; fileRef = C0EE9A7E2863BDE300738B6B /* JamfProAPITypes.swift */; };
C0EE9A812863BE2B00738B6B /* NetworkAuthManager.swift in Sources */ = {isa = PBXBuildFile; fileRef = C0EE9A802863BE2B00738B6B /* NetworkAuthManager.swift */; };
C0EE9A832863BEEB00738B6B /* URLSessionAsyncCompatibility.swift in Sources */ = {isa = PBXBuildFile; fileRef = C0EE9A822863BEEB00738B6B /* URLSessionAsyncCompatibility.swift */; };
/* End PBXBuildFile section */

/* Begin PBXContainerItemProxy section */
Expand Down Expand Up @@ -131,7 +130,6 @@
C0EE9A7C28639BF800738B6B /* TestTCCProfileForJamfProAPI.txt */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; path = TestTCCProfileForJamfProAPI.txt; sourceTree = "<group>"; };
C0EE9A7E2863BDE300738B6B /* JamfProAPITypes.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = JamfProAPITypes.swift; sourceTree = "<group>"; };
C0EE9A802863BE2B00738B6B /* NetworkAuthManager.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = NetworkAuthManager.swift; sourceTree = "<group>"; };
C0EE9A822863BEEB00738B6B /* URLSessionAsyncCompatibility.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = URLSessionAsyncCompatibility.swift; sourceTree = "<group>"; };
/* End PBXFileReference section */

/* Begin PBXFrameworksBuildPhase section */
Expand Down Expand Up @@ -324,7 +322,6 @@
C03270BF28636397008B38E0 /* JamfProAPIClient.swift */,
C0EE9A7E2863BDE300738B6B /* JamfProAPITypes.swift */,
C05844B72AD4512D00141353 /* Token.swift */,
C0EE9A822863BEEB00738B6B /* URLSessionAsyncCompatibility.swift */,
);
path = Networking;
sourceTree = "<group>";
Expand Down Expand Up @@ -512,7 +509,6 @@
6E6216F9215321CE0043DF18 /* OpenViewController.swift in Sources */,
C05844B82AD4512D00141353 /* Token.swift in Sources */,
6EC40A10214DE3B200BE4F17 /* Executable.swift in Sources */,
C0EE9A832863BEEB00738B6B /* URLSessionAsyncCompatibility.swift in Sources */,
C0EE9A812863BE2B00738B6B /* NetworkAuthManager.swift in Sources */,
6EC40A16214ECF1E00BE4F17 /* SaveViewController.swift in Sources */,
C05844BE2AD45F7900141353 /* UploadInfoView.swift in Sources */,
Expand Down Expand Up @@ -644,7 +640,7 @@
GCC_WARN_UNUSED_FUNCTION = YES;
GCC_WARN_UNUSED_VARIABLE = YES;
IBSC_NOTICES = NO;
MACOSX_DEPLOYMENT_TARGET = 11.0;
MACOSX_DEPLOYMENT_TARGET = 13.0;
MTL_ENABLE_DEBUG_INFO = INCLUDE_SOURCE;
MTL_FAST_MATH = YES;
ONLY_ACTIVE_ARCH = YES;
Expand Down Expand Up @@ -700,7 +696,7 @@
GCC_WARN_UNUSED_FUNCTION = YES;
GCC_WARN_UNUSED_VARIABLE = YES;
IBSC_NOTICES = NO;
MACOSX_DEPLOYMENT_TARGET = 11.0;
MACOSX_DEPLOYMENT_TARGET = 13.0;
MTL_ENABLE_DEBUG_INFO = NO;
MTL_FAST_MATH = YES;
SDKROOT = macosx;
Expand Down
196 changes: 2 additions & 194 deletions PPPC UtilityTests/ModelTests/ModelTests.swift
Original file line number Diff line number Diff line change
Expand Up @@ -130,7 +130,6 @@ class ModelTests: XCTestCase {

func testExportProfileWithAppleEventsAndAuthorization() {
// given
model.usingLegacyAllowKey = false
let exe1 = Executable(identifier: "one", codeRequirement: "oneReq")
let exe2 = Executable(identifier: "two", codeRequirement: "twoReq")

Expand Down Expand Up @@ -185,60 +184,6 @@ class ModelTests: XCTestCase {
}
}

func testExportProfileWithAppleEventsAndLegacyAllowed() {
// given
let exe1 = Executable(identifier: "one", codeRequirement: "oneReq")
let exe2 = Executable(identifier: "two", codeRequirement: "twoReq")
exe1.appleEvents = [AppleEventRule(source: exe1, destination: exe2, value: true)]
exe2.policy.SystemPolicyAllFiles = "Allow"
model.selectedExecutables = [exe1, exe2]
model.usingLegacyAllowKey = true

// when
let profile = model.exportProfile(organization: "Org", identifier: "ID", displayName: "Name", payloadDescription: "Desc")

// then check top level settings
XCTAssertEqual("Org", profile.organization)
XCTAssertEqual("ID", profile.identifier)
XCTAssertEqual("Name", profile.displayName)
XCTAssertEqual("Desc", profile.payloadDescription)
XCTAssertEqual("System", profile.scope)
XCTAssertEqual("Configuration", profile.type)
XCTAssertNotNil(profile.uuid)
XCTAssertEqual(1, profile.version)

// then verify the payload content top level
XCTAssertEqual(1, profile.content.count)
profile.content.forEach { content in
XCTAssertNotNil(content.uuid)
XCTAssertEqual(1, content.version)

// then verify the services
XCTAssertEqual(2, content.services.count)
let appleEventsPolicy = content.services["AppleEvents"]?.first
XCTAssertNotNil(appleEventsPolicy)
XCTAssertEqual("one", appleEventsPolicy?.identifier)
XCTAssertEqual("oneReq", appleEventsPolicy?.codeRequirement)
XCTAssertEqual("bundleID", appleEventsPolicy?.identifierType)
XCTAssertEqual("two", appleEventsPolicy?.receiverIdentifier)
XCTAssertEqual("twoReq", appleEventsPolicy?.receiverCodeRequirement)
XCTAssertEqual("bundleID", appleEventsPolicy?.receiverIdentifierType)
XCTAssertTrue(appleEventsPolicy?.allowed == true)
XCTAssertNil(appleEventsPolicy?.authorization)

let allFilesPolicy = content.services["SystemPolicyAllFiles"]?.first
XCTAssertNotNil(allFilesPolicy)
XCTAssertEqual("two", allFilesPolicy?.identifier)
XCTAssertEqual("twoReq", allFilesPolicy?.codeRequirement)
XCTAssertEqual("bundleID", allFilesPolicy?.identifierType)
XCTAssertNil(allFilesPolicy?.receiverIdentifier)
XCTAssertNil(allFilesPolicy?.receiverCodeRequirement)
XCTAssertNil(allFilesPolicy?.receiverIdentifierType)
XCTAssertTrue(allFilesPolicy?.allowed == true)
XCTAssertNil(allFilesPolicy?.authorization)
}
}

// MARK: - tests for importProfile

func testImportProfileUsingAuthorizationKeyAllow() {
Expand Down Expand Up @@ -325,11 +270,10 @@ class ModelTests: XCTestCase {
XCTAssertEqual("Deny", model.selectedExecutables.first?.policy.SystemPolicyAllFiles)
}

// MARK: - tests for profileToString
// MARK: - tests for policyFromString

func testPolicyWhenUsingAllowAndAuthorizationKey() {
func testPolicyWhenUsingAllow() {
// given
model.usingLegacyAllowKey = false
let app = Executable(identifier: "id", codeRequirement: "req")

// when
Expand All @@ -342,7 +286,6 @@ class ModelTests: XCTestCase {

func testPolicyWhenUsingDeny() {
// given
model.usingLegacyAllowKey = false
let app = Executable(identifier: "id", codeRequirement: "req")

// when
Expand All @@ -355,7 +298,6 @@ class ModelTests: XCTestCase {

func testPolicyWhenUsingAllowForStandardUsers() {
// given
model.usingLegacyAllowKey = false
let app = Executable(identifier: "id", codeRequirement: "req")

// when
Expand All @@ -377,138 +319,4 @@ class ModelTests: XCTestCase {
XCTAssertNil(policy, "should have not created the policy with an unknown value")
}

func testPolicyWhenUsingLegacyDeny() {
// given
let app = Executable(identifier: "id", codeRequirement: "req")
model.usingLegacyAllowKey = true

// when
let policy = model.policyFromString(executable: app, value: "Deny")

// then
XCTAssertNil(policy?.authorization, "should not set authorization when in legacy mode")
XCTAssertEqual(policy?.allowed, false)
}

func testPolicyWhenUsingLegacyAllow() {
// given
let app = Executable(identifier: "id", codeRequirement: "req")
model.usingLegacyAllowKey = true

// when
let policy = model.policyFromString(executable: app, value: "Allow")

// then
XCTAssertNil(policy?.authorization, "should not set authorization when in legacy mode")
XCTAssertEqual(policy?.allowed, true)
}

// test for the unrecognized strings for both legacy and normal
func testPolicyWhenUsingLegacyAllowButNonLegacyValueUsed() {
// given
let app = Executable(identifier: "id", codeRequirement: "req")
model.usingLegacyAllowKey = true

// when
let policy = model.policyFromString(executable: app, value: "Let Standard Users Approve")

// then
XCTAssertNil(policy, "should have errored out because of an invalid value")
}

// MARK: - tests for requiresAuthorizationKey

func testWhenServiceIsUsingAllowStandarUsersToApprove() {
// given
let profile = TCCProfileBuilder().buildProfile(authorization: .allowStandardUserToSetSystemService)

// when
model.importProfile(tccProfile: profile)

// then
XCTAssertTrue(model.requiresAuthorizationKey())
}

func testWhenServiceIsUsingOnlyAllowKey() {
// given
let profile = TCCProfileBuilder().buildProfile(authorization: .allow)

// when
model.importProfile(tccProfile: profile)

// then
XCTAssertFalse(model.requiresAuthorizationKey())
}

func testWhenServiceIsUsingOnlyDenyKey() {
// given
let profile = TCCProfileBuilder().buildProfile(authorization: .deny)

// when
model.importProfile(tccProfile: profile)

// then
XCTAssertFalse(model.requiresAuthorizationKey())
}

// MARK: - tests for changeToUseLegacyAllowKey

func testChangingFromAuthorizationKeyToLegacyAllowKey() {
// given
let allowStandard = TCCProfileDisplayValue.allowStandardUsersToApprove.rawValue
let exeSettings = ["AddressBook": "Allow", "ListenEvent": allowStandard, "ScreenCapture": allowStandard]
let model = ModelBuilder().addExecutable(settings: exeSettings).build()
model.usingLegacyAllowKey = false

// when
model.changeToUseLegacyAllowKey()

// then
XCTAssertEqual(1, model.selectedExecutables.count, "should have only one exe")
let policy = model.selectedExecutables.first?.policy
XCTAssertEqual("Allow", policy?.AddressBook)
XCTAssertEqual("-", policy?.Camera)
XCTAssertEqual("-", policy?.ListenEvent)
XCTAssertEqual("-", policy?.ScreenCapture)
XCTAssertTrue(model.usingLegacyAllowKey)
}

func testChangingFromAuthorizationKeyToLegacyAllowKeyWithMoreComplexVaues() {
// given
let allowStandard = TCCProfileDisplayValue.allowStandardUsersToApprove.rawValue
let p1Settings = [
"SystemPolicyAllFiles": "Allow",
"ListenEvent": allowStandard,
"ScreenCapture": "Deny",
"Camera": "Deny"
]

let p2Settings = [
"SystemPolicyAllFiles": "Deny",
"ScreenCapture": allowStandard,
"Calendar": "Allow"
]
let builder = ModelBuilder().addExecutable(settings: p1Settings)
model = builder.addExecutable(settings: p2Settings).build()
model.usingLegacyAllowKey = false

// when
model.changeToUseLegacyAllowKey()

// then
XCTAssertEqual(2, model.selectedExecutables.count, "should have only one exe")
let policy1 = model.selectedExecutables[0].policy
XCTAssertEqual("Allow", policy1.SystemPolicyAllFiles)
XCTAssertEqual("-", policy1.ListenEvent)
XCTAssertEqual("Deny", policy1.ScreenCapture)
XCTAssertEqual("Deny", policy1.Camera)

let policy2 = model.selectedExecutables[1].policy
XCTAssertEqual("Deny", policy2.SystemPolicyAllFiles)
XCTAssertEqual("-", policy2.ListenEvent)
XCTAssertEqual("-", policy2.ScreenCapture)
XCTAssertEqual("Allow", policy2.Calendar)
XCTAssertTrue(model.usingLegacyAllowKey)
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -85,7 +85,7 @@ class PPPCServicesManagerTests: XCTestCase {
let service = try XCTUnwrap(services.allServices["ScreenCapture"])

// when
let actual = try XCTUnwrap(service.allowStandardUsersMacOS11Plus)
let actual = try XCTUnwrap(service.allowStandardUsers)

// then
XCTAssertTrue(actual)
Expand Down
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@

[logo]: /Resources/Assets.xcassets/AppIcon.appiconset/PPPC_Logo_32%402x.png "PPPC Utility"

PPPC Utility is a macOS (10.15 and newer) application for creating configuration profiles containing the Privacy Preferences Policy Control payload for macOS. The profiles can be saved locally, signed or unsigned. Profiles can also be uploaded directly to a Jamf Pro server.
PPPC Utility is a macOS (13.0 and newer) application for creating configuration profiles containing the Privacy Preferences Policy Control payload for macOS. The profiles can be saved locally, signed or unsigned. Profiles can also be uploaded directly to a Jamf Pro server.

All changes to the application are tracked in [the changelog](https://github.com/jamf/PPPC-Utility/blob/master/CHANGELOG.md).

Expand Down
Loading
Loading