Skip to content
Closed
10 changes: 4 additions & 6 deletions PPPC UtilityTests/ModelTests/ModelTests.swift
Original file line number Diff line number Diff line change
Expand Up @@ -218,9 +218,8 @@ class ModelTests: XCTestCase {

// then verify the services
XCTAssertEqual(2, content.services.count)
let appleEvents = content.services["AppleEvents"]
XCTAssertNotNil(appleEvents)
let appleEventsPolicy = appleEvents?.first
let appleEventsPolicy = content.services["AppleEvents"]?.first
XCTAssertNotNil(appleEventsPolicy)
XCTAssertEqual("one", appleEventsPolicy?.identifier)
XCTAssertEqual("oneReq", appleEventsPolicy?.codeRequirement)
XCTAssertEqual("bundleID", appleEventsPolicy?.identifierType)
Expand All @@ -230,9 +229,8 @@ class ModelTests: XCTestCase {
XCTAssertTrue(appleEventsPolicy?.allowed == true)
XCTAssertNil(appleEventsPolicy?.authorization)

let allFiles = content.services["SystemPolicyAllFiles"]
XCTAssertNotNil(allFiles)
let allFilesPolicy = allFiles?.first
let allFilesPolicy = content.services["SystemPolicyAllFiles"]?.first
XCTAssertNotNil(allFilesPolicy)
XCTAssertEqual("two", allFilesPolicy?.identifier)
XCTAssertEqual("twoReq", allFilesPolicy?.codeRequirement)
XCTAssertEqual("bundleID", allFilesPolicy?.identifierType)
Expand Down
94 changes: 59 additions & 35 deletions Source/SwiftUI/UploadInfoView.swift
Original file line number Diff line number Diff line change
Expand Up @@ -12,11 +12,13 @@ struct UploadInfoView: View {
/// The signing identities available to be used.
let signingIdentities: [SigningIdentity]
/// Function to call when this view needs to be removed
let dismissAction: (() -> Void)?
let dismissAction: () -> Void

// Communicate this info to the user
@State private var warningInfo: String?
@State private var networkOperationInfo: String?
/// Tracks whether the view has been dismissed to guard async callbacks
@State private var isDismissed = false
/// Must sign the profile if Jamf Pro is less than v10.7.1
@State private var mustSign = false
/// The hash of connection info that has been verified with a succesful connection
Expand Down Expand Up @@ -147,6 +149,9 @@ struct UploadInfoView: View {
payloadId = tccProfile.identifier
}
}
.onDisappear {
isDismissed = true
}
}

/// Creates a hash of the currently entered connection info
Expand Down Expand Up @@ -275,43 +280,61 @@ struct UploadInfoView: View {
guard connectionInfoPassesValidation(setWarningInfo: true) else {
return
}

let requestHash = hashOfConnectionInfo
networkOperationInfo = "Checking Jamf Pro server"

let uploadMgr = UploadManager(serverURL: serverURL)
uploadMgr.verifyConnection(authManager: makeAuthManager()) { result in
if case .success(let success) = result {
mustSign = success.mustSign
organization = success.organization
verifiedConnectionHash = hashOfConnectionInfo
if saveToKeychain {
do {
try SecurityWrapper.saveCredentials(username: username,
password: password,
server: serverURL)
} catch {
logger.error("Failed to save credentials with error: \(error.localizedDescription)")
Task { @MainActor in
guard !isDismissed, requestHash == hashOfConnectionInfo else { return }

switch result {
case .success(let success):
mustSign = success.mustSign
organization = success.organization
verifiedConnectionHash = requestHash
if saveToKeychain {
let user = username
let pass = password
let server = serverURL
Task.detached {
do {
try SecurityWrapper.saveCredentials(username: user,
password: pass,
server: server)
} catch {
logger.error("Failed to save credentials with error: \(error.localizedDescription)")
}
}
}
case .failure(let failure):
if case .anyError(let errorString) = failure {
warningInfo = errorString
}
verifiedConnectionHash = 0
}
// Future on macOS 12+: focus on Payload Name field
} else if case .failure(let failure) = result,
case .anyError(let errorString) = failure {
warningInfo = errorString
verifiedConnectionHash = 0
}

networkOperationInfo = nil
networkOperationInfo = nil
}
}
}

private func dismissView() {
if !saveToKeychain {
try? SecurityWrapper.removeCredentials(server: serverURL, username: username)
}
// Capture values needed for potential background credential removal
let shouldRemoveCredentials = !saveToKeychain
let server = serverURL
let user = username

if let dismiss = dismissAction {
dismiss()
}
isDismissed = true

// Dismiss the view immediately to keep the UI responsive
dismissAction()

if shouldRemoveCredentials {
Task.detached {
try? SecurityWrapper.removeCredentials(server: server, username: user)
}
}
}

func performUpload() {
Expand Down Expand Up @@ -342,18 +365,19 @@ struct UploadInfoView: View {
authMgr: makeAuthManager(),
siteInfo: siteIdAndName,
signingIdentity: mustSign ? signingId : nil) { possibleError in
if let error = possibleError {
warningInfo = error.localizedDescription
} else {
Alert().display(header: "Success", message: "Profile uploaded succesfully")
dismissView()
}
networkOperationInfo = nil
guard !isDismissed else { return }

if let error = possibleError {
warningInfo = error.localizedDescription
} else {
Alert().display(header: "Success", message: "Profile uploaded successfully")
dismissView()
}
networkOperationInfo = nil
}
}
}

#Preview {
UploadInfoView(signingIdentities: [],
dismissAction: nil)
UploadInfoView(signingIdentities: []) {}
}
13 changes: 7 additions & 6 deletions Source/View Controllers/TCCProfileViewController.swift
Original file line number Diff line number Diff line change
Expand Up @@ -188,13 +188,14 @@ class TCCProfileViewController: NSViewController {
logger.error("Error loading identities: \(error.localizedDescription)")
}

let uploadView = UploadInfoView(signingIdentities: identities) {
// Dismiss the sheet when the UploadInfoView decides it is done
if let controller = self.presentedViewControllers?.first {
self.dismiss(controller)
}
let hostingController = NSHostingController(
rootView: UploadInfoView(signingIdentities: identities) {}
)
hostingController.rootView = UploadInfoView(signingIdentities: identities) { [weak self, weak hostingController] in
guard let self, let controller = hostingController else { return }
self.dismiss(controller)
}
self.presentAsSheet(NSHostingController(rootView: uploadView))
self.presentAsSheet(hostingController)
}

fileprivate func showAlert(_ error: LocalizedError, for window: NSWindow) {
Expand Down
Loading