From e9bc4cc5d3ce401c2e78ce0fcb7c6da6adb99b3b Mon Sep 17 00:00:00 2001 From: Serhiy Mytrovtsiy Date: Fri, 18 Nov 2022 22:51:34 +0100 Subject: [PATCH] feat: moved from the AppleScript for asking a root access when manipulating the fans to the Helper (SMJobBless + XPC) (#1173) --- Kit/helpers.swift | 147 +++++++++++----- Kit/scripts/uninstall.sh | 5 + Modules/Sensors/main.swift | 4 +- Modules/Sensors/popup.swift | 10 +- SMC/Helper/Info.plist | 18 ++ SMC/Helper/Launchd.plist | 13 ++ SMC/Helper/main.swift | 97 +++++++++++ SMC/Helper/protocol.swift | 20 +++ SMC/main.swift | 17 +- Stats.xcodeproj/project.pbxproj | 157 +++++++++++++++++- .../xcshareddata/xcschemes/Stats.xcscheme | 14 ++ Stats/Supporting Files/Info.plist | 5 + 12 files changed, 443 insertions(+), 64 deletions(-) create mode 100644 Kit/scripts/uninstall.sh create mode 100644 SMC/Helper/Info.plist create mode 100644 SMC/Helper/Launchd.plist create mode 100644 SMC/Helper/main.swift create mode 100644 SMC/Helper/protocol.swift diff --git a/Kit/helpers.swift b/Kit/helpers.swift index 93e0e97c..06288b9a 100644 --- a/Kit/helpers.swift +++ b/Kit/helpers.swift @@ -1002,66 +1002,127 @@ public class SettingsContainerView: NSStackView { public class SMCHelper { public static let shared = SMCHelper() - private let smc: String - - public init() { - self.smc = Bundle.main.path(forResource: "smc", ofType: nil)! - } + private var connection: NSXPCConnection? = nil public func setFanSpeed(_ id: Int, speed: Int) { - if !self.checkRights() { - if !self.ensureRights() { - return + helperStatus { installed in + if !installed { + self.install() + } + guard let helper = self.helper(nil) else { return } + + helper.setFanSpeed(id: id, value: speed) { result in + if let result, !result.isEmpty { + print(result) + } } } - - _ = syncShell("\(self.smc) fan -id \(id) -v \(speed)") } public func setFanMode(_ id: Int, mode: Int) { - if !self.checkRights() { - if !self.ensureRights() { - return - } - } - - _ = syncShell("\(self.smc) fan -id \(id) -m \(mode)") - } - - public func checkRights() -> Bool { - do { - let attributes = try FileManager.default.attributesOfItem(atPath: self.smc) - guard let owner = attributes[FileAttributeKey(rawValue: "NSFileOwnerAccountName")] as? String, - let ownerGroup = attributes[FileAttributeKey(rawValue: "NSFileGroupOwnerAccountName")] as? String, - let permissions = attributes[FileAttributeKey(rawValue: "NSFilePosixPermissions")] as? Int else { - print("some of the smc attributes is missing") - return false + helperStatus { installed in + if !installed { + self.install() } + guard let helper = self.helper(nil) else { return } - if owner == "root" && ownerGroup == "admin" && permissions == 3437 { - return true + helper.setFanMode(id: id, mode: mode) { result in + if let result, !result.isEmpty { + print(result) + } } - } catch let error { - print("get smc attributes, \(error)") - return false } - - return false } - private func ensureRights() -> Bool { - guard let script = NSAppleScript(source: "do shell script \"/usr/sbin/chown root:admin \(self.smc) && /bin/chmod 6555 \(self.smc)\" with administrator privileges") else { - return false + public func isActive() -> Bool { + return self.connection != nil + } + + private func helperStatus(completion: @escaping (_ installed: Bool) -> Void) { + let helperURL = Bundle.main.bundleURL.appendingPathComponent("Contents/Library/LaunchServices/eu.exelban.Stats.SMC.Helper") + guard + let helperBundleInfo = CFBundleCopyInfoDictionaryForURL(helperURL as CFURL) as? [String: Any], + let helperVersion = helperBundleInfo["CFBundleShortVersionString"] as? String, + let helper = self.helper(completion) else { + completion(false) + return } - var err: NSDictionary? = nil - script.executeAndReturnError(&err) - if err != nil { - print("cannot upgrade owner to root: \(String(describing: err))") - return false + helper.version { installedHelperVersion in + completion(installedHelperVersion == helperVersion) + } + } + + private func install() { + var authRef: AuthorizationRef? + var authStatus = AuthorizationCreate(nil, nil, [.preAuthorize], &authRef) + + guard authStatus == errAuthorizationSuccess else { + print("Unable to get a valid empty authorization reference to load Helper daemon") + return } - return true + let authItem = kSMRightBlessPrivilegedHelper.withCString { authorizationString in + AuthorizationItem(name: authorizationString, valueLength: 0, value: nil, flags: 0) + } + + let pointer = UnsafeMutablePointer.allocate(capacity: 1) + pointer.initialize(to: authItem) + + defer { + pointer.deinitialize(count: 1) + pointer.deallocate() + } + + var authRights = AuthorizationRights(count: 1, items: pointer) + + let flags: AuthorizationFlags = [.interactionAllowed, .extendRights, .preAuthorize] + authStatus = AuthorizationCreate(&authRights, nil, flags, &authRef) + + guard authStatus == errAuthorizationSuccess else { + print("Unable to get a valid loading authorization reference to load Helper daemon") + return + } + + var error: Unmanaged? + if SMJobBless(kSMDomainUserLaunchd, "eu.exelban.Stats.SMC.Helper" as CFString, authRef, &error) == false { + let blessError = error!.takeRetainedValue() as Error + print("Error while installing the Helper: \(blessError.localizedDescription)") + return + } + + AuthorizationFree(authRef!, []) + } + + private func helperConnection() -> NSXPCConnection? { + guard self.connection == nil else { + return self.connection + } + + let connection = NSXPCConnection(machServiceName: "eu.exelban.Stats.SMC.Helper", options: .privileged) + connection.exportedObject = self + connection.remoteObjectInterface = NSXPCInterface(with: HelperProtocol.self) + connection.invalidationHandler = { + self.connection?.invalidationHandler = nil + OperationQueue.main.addOperation { + self.connection = nil + } + } + + self.connection = connection + self.connection?.resume() + + return self.connection + } + + private func helper(_ completion: ((Bool) -> Void)?) -> HelperProtocol? { + guard let helper = self.helperConnection()?.remoteObjectProxyWithErrorHandler({ _ in + if let onCompletion = completion { onCompletion(false) } + }) as? HelperProtocol else { return nil } + + helper.setSMCPath(Bundle.main.path(forResource: "smc", ofType: nil)!) + + return helper } } diff --git a/Kit/scripts/uninstall.sh b/Kit/scripts/uninstall.sh new file mode 100644 index 00000000..3c1c0156 --- /dev/null +++ b/Kit/scripts/uninstall.sh @@ -0,0 +1,5 @@ +#! /bin/sh + +sudo launchctl unload /Library/LaunchDaemons/eu.exelban.Stats.SMC.Helper.plist +sudo rm /Library/LaunchDaemons/eu.exelban.Stats.SMC.Helper.plist +sudo rm /Library/PrivilegedHelperTools/eu.exelban.Stats.SMC.Helper diff --git a/Modules/Sensors/main.swift b/Modules/Sensors/main.swift index 3c76e0b5..fa04e639 100644 --- a/Modules/Sensors/main.swift +++ b/Modules/Sensors/main.swift @@ -57,9 +57,7 @@ public class Sensors: Module { } public override func willTerminate() { - if !SMCHelper.shared.checkRights() { - return - } + guard SMCHelper.shared.isActive() else { return } self.sensorsReader.list.filter({ $0 is Fan }).forEach { (s: Sensor_p) in if let f = s as? Fan, let mode = f.customMode { diff --git a/Modules/Sensors/popup.swift b/Modules/Sensors/popup.swift index 1510d458..d68f62ff 100644 --- a/Modules/Sensors/popup.swift +++ b/Modules/Sensors/popup.swift @@ -313,9 +313,7 @@ internal class FanView: NSStackView { private var maxBtn: NSButton? = nil private var speedState: Bool { - get { - return Store.shared.bool(key: "Sensors_speed", defaultValue: false) - } + Store.shared.bool(key: "Sensors_speed", defaultValue: false) } private var speed: Double { get { @@ -328,9 +326,7 @@ internal class FanView: NSStackView { private var resetModeAfterSleep: Bool = false private var horizontalMargin: CGFloat { - get { - return self.edgeInsets.top + self.edgeInsets.bottom + (self.spacing*CGFloat(self.arrangedSubviews.count)) - } + self.edgeInsets.top + self.edgeInsets.bottom + (self.spacing*CGFloat(self.arrangedSubviews.count)) } private var willSleepMode: FanMode? = nil @@ -634,7 +630,7 @@ internal class FanView: NSStackView { } @objc private func sleepListener(aNotification: NSNotification) { - guard SMCHelper.shared.checkRights() && self.fan.customMode != .automatic else { return } + guard SMCHelper.shared.isActive() && self.fan.customMode != .automatic else { return } self.willSleepMode = self.fan.customMode self.willSleepSpeed = self.fan.customSpeed diff --git a/SMC/Helper/Info.plist b/SMC/Helper/Info.plist new file mode 100644 index 00000000..9363c2f2 --- /dev/null +++ b/SMC/Helper/Info.plist @@ -0,0 +1,18 @@ + + + + + CFBundleIdentifier + eu.exelban.Stats.SMC.Helper + CFBundleName + eu.exelban.Stats.SMC.Helper + CFBundleShortVersionString + 1.0 + CFBundleVersion + 1 + SMAuthorizedClients + + identifier "eu.exelban.Stats" and anchor apple generic and certificate 1[field.1.2.840.113635.100.6.2.1] /* exists */ + + + diff --git a/SMC/Helper/Launchd.plist b/SMC/Helper/Launchd.plist new file mode 100644 index 00000000..64d8a7b4 --- /dev/null +++ b/SMC/Helper/Launchd.plist @@ -0,0 +1,13 @@ + + + + + Label + eu.exelban.Stats.SMC.Helper + MachServices + + eu.exelban.Stats.SMC.Helper + + + + diff --git a/SMC/Helper/main.swift b/SMC/Helper/main.swift new file mode 100644 index 00000000..02206c87 --- /dev/null +++ b/SMC/Helper/main.swift @@ -0,0 +1,97 @@ +// +// main.swift +// Helper +// +// Created by Serhiy Mytrovtsiy on 17/11/2022 +// Using Swift 5.0 +// Running on macOS 13.0 +// +// Copyright © 2022 Serhiy Mytrovtsiy. All rights reserved. +// + +import Foundation + +let helper = Helper() +helper.run() + +class Helper: NSObject, NSXPCListenerDelegate, HelperProtocol { + private let listener: NSXPCListener + + private var connections = [NSXPCConnection]() + private var shouldQuit = false + private var shouldQuitCheckInterval = 1.0 + + private var smc: String? = nil + + override init() { + self.listener = NSXPCListener(machServiceName: "eu.exelban.Stats.SMC.Helper") + super.init() + self.listener.delegate = self + } + + public func run() { + self.listener.resume() + while !self.shouldQuit { + RunLoop.current.run(until: Date(timeIntervalSinceNow: self.shouldQuitCheckInterval)) + } + } + + func listener(_ listener: NSXPCListener, shouldAcceptNewConnection connection: NSXPCConnection) -> Bool { + connection.exportedInterface = NSXPCInterface(with: HelperProtocol.self) + connection.exportedObject = self + connection.invalidationHandler = { + if let connectionIndex = self.connections.firstIndex(of: connection) { + self.connections.remove(at: connectionIndex) + } + if self.connections.isEmpty { + self.shouldQuit = true + } + } + + self.connections.append(connection) + connection.resume() + + return true + } +} + +extension Helper { + func version(completion: (String) -> Void) { + completion(Bundle.main.object(forInfoDictionaryKey: "CFBundleShortVersionString") as? String ?? "0") + } + func setSMCPath(_ path: String) { + self.smc = path + } + + func setFanMode(id: Int, mode: Int, completion: (String?) -> Void) { + guard let smc = self.smc else { + completion("missing smc tool") + return + } + let result = syncShell("\(smc) fan \(id) -m \(mode)") + completion(result) + } + + func setFanSpeed(id: Int, value: Int, completion: (String?) -> Void) { + guard let smc = self.smc else { + completion("missing smc tool") + return + } + let result = syncShell("\(smc) fan \(id) -v \(value)") + completion(result) + } + + public func syncShell(_ args: String) -> String { + let task = Process() + task.launchPath = "/bin/sh" + task.arguments = ["-c", args] + let pipe = Pipe() + + task.standardOutput = pipe + task.launch() + task.waitUntilExit() + + let data = pipe.fileHandleForReading.readDataToEndOfFile() + return String(data: data, encoding: .utf8)! + } +} diff --git a/SMC/Helper/protocol.swift b/SMC/Helper/protocol.swift new file mode 100644 index 00000000..291b083e --- /dev/null +++ b/SMC/Helper/protocol.swift @@ -0,0 +1,20 @@ +// +// protocol.swift +// Helper +// +// Created by Serhiy Mytrovtsiy on 17/11/2022 +// Using Swift 5.0 +// Running on macOS 13.0 +// +// Copyright © 2022 Serhiy Mytrovtsiy. All rights reserved. +// + +import Foundation + +@objc public protocol HelperProtocol { + func version(completion: @escaping (String) -> Void) + func setSMCPath(_ path: String) + + func setFanMode(id: Int, mode: Int, completion: @escaping (String?) -> Void) + func setFanSpeed(id: Int, value: Int, completion: @escaping (String?) -> Void) +} diff --git a/SMC/main.swift b/SMC/main.swift index 0d5abe87..6f53d711 100644 --- a/SMC/main.swift +++ b/SMC/main.swift @@ -97,25 +97,28 @@ func main() { print("[INFO]: set \(value) on \(key)") case .fan: - guard let idIndex = args.firstIndex(where: { $0 == "-id" }), - args.indices.contains(idIndex+1), - let id = Int(args[idIndex+1]) else { - print("[ERROR]: missing id") + guard let idString = args.first, let id = Int(idString) else { + print("[ERROR]: missing fan id") return } + var help: Bool = true if let index = args.firstIndex(where: { $0 == "-v" }), args.indices.contains(index+1), let value = Int(args[index+1]) { SMC.shared.setFanSpeed(id, speed: value) - return + help = false } if let index = args.firstIndex(where: { $0 == "-m" }), args.indices.contains(index+1), let raw = Int(args[index+1]), let mode = FanMode.init(rawValue: raw) { SMC.shared.setFanMode(id, mode: mode) - return + help = false } - print("[ERROR]: missing value or mode") + guard help else { return } + + print("Available Flags:") + print(" -m change the fan mode: 0 - automatic, 1 - manual") + print(" -v change the fan speed") case .fans: guard let count = SMC.shared.getValue("FNum") else { print("FNum not found") diff --git a/Stats.xcodeproj/project.pbxproj b/Stats.xcodeproj/project.pbxproj index 9effc50f..0e61b4a3 100644 --- a/Stats.xcodeproj/project.pbxproj +++ b/Stats.xcodeproj/project.pbxproj @@ -7,6 +7,12 @@ objects = { /* Begin PBXBuildFile section */ + 5C8E001029269C7F0027C75A /* protocol.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5CFE493829265055000F2856 /* protocol.swift */; }; + 5CFE492A29264DF1000F2856 /* main.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5CFE492929264DF1000F2856 /* main.swift */; }; + 5CFE493929265055000F2856 /* protocol.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5CFE493829265055000F2856 /* protocol.swift */; }; + 5CFE493D2926513E000F2856 /* eu.exelban.Stats.SMC.Helper in CopyFiles */ = {isa = PBXBuildFile; fileRef = 5CFE492729264DF1000F2856 /* eu.exelban.Stats.SMC.Helper */; settings = {ATTRIBUTES = (CodeSignOnCopy, ); }; }; + 5CFE494229265418000F2856 /* uninstall.sh in Resources */ = {isa = PBXBuildFile; fileRef = 5CFE494129265418000F2856 /* uninstall.sh */; }; + 5CFE494429265421000F2856 /* changelog.py in Resources */ = {isa = PBXBuildFile; fileRef = 5CFE494329265421000F2856 /* changelog.py */; }; 9A045EB72594F8D100ED58F2 /* Dashboard.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9A045EB62594F8D100ED58F2 /* Dashboard.swift */; }; 9A11AAD6266FD77F000C1C05 /* Bluetooth.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 9A11AACF266FD77F000C1C05 /* Bluetooth.framework */; }; 9A11AAD7266FD77F000C1C05 /* Bluetooth.framework in Embed Frameworks */ = {isa = PBXBuildFile; fileRef = 9A11AACF266FD77F000C1C05 /* Bluetooth.framework */; settings = {ATTRIBUTES = (CodeSignOnCopy, RemoveHeadersOnCopy, ); }; }; @@ -259,6 +265,25 @@ /* End PBXContainerItemProxy section */ /* Begin PBXCopyFilesBuildPhase section */ + 5CFE492529264DF1000F2856 /* CopyFiles */ = { + isa = PBXCopyFilesBuildPhase; + buildActionMask = 2147483647; + dstPath = /usr/share/man/man1/; + dstSubfolderSpec = 0; + files = ( + ); + runOnlyForDeploymentPostprocessing = 1; + }; + 5CFE493C29265130000F2856 /* CopyFiles */ = { + isa = PBXCopyFilesBuildPhase; + buildActionMask = 2147483647; + dstPath = Contents/Library/LaunchServices; + dstSubfolderSpec = 1; + files = ( + 5CFE493D2926513E000F2856 /* eu.exelban.Stats.SMC.Helper in CopyFiles */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; 9A46BF89266D7CFA001A1117 /* CopyFiles */ = { isa = PBXCopyFilesBuildPhase; buildActionMask = 2147483647; @@ -317,6 +342,13 @@ 30370F8F253DCBC0006404D8 /* zh-Hant */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = "zh-Hant"; path = "zh-Hant.lproj/Localizable.strings"; sourceTree = ""; }; 40BE2B202745D63800AE9396 /* da */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = da; path = da.lproj/Localizable.strings; sourceTree = ""; }; 4921436D25319699000A1C47 /* ko */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = ko; path = ko.lproj/Localizable.strings; sourceTree = ""; }; + 5CFE492729264DF1000F2856 /* eu.exelban.Stats.SMC.Helper */ = {isa = PBXFileReference; explicitFileType = "compiled.mach-o.executable"; includeInIndex = 0; path = eu.exelban.Stats.SMC.Helper; sourceTree = BUILT_PRODUCTS_DIR; }; + 5CFE492929264DF1000F2856 /* main.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = main.swift; sourceTree = ""; }; + 5CFE493829265055000F2856 /* protocol.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = protocol.swift; sourceTree = ""; }; + 5CFE493A292650BD000F2856 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; + 5CFE493B292650F8000F2856 /* Launchd.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Launchd.plist; sourceTree = ""; }; + 5CFE494129265418000F2856 /* uninstall.sh */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.script.sh; path = uninstall.sh; sourceTree = ""; }; + 5CFE494329265421000F2856 /* changelog.py */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.script.python; path = changelog.py; sourceTree = ""; }; 62BA5F74254810C8009D0AC2 /* es */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = es; path = es.lproj/Localizable.strings; sourceTree = ""; }; 63A07F97275018DF00352C46 /* ca */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = ca; path = ca.lproj/Localizable.strings; sourceTree = ""; }; 7A19DAE52552C326001B192F /* fr */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = fr; path = fr.lproj/Localizable.strings; sourceTree = ""; }; @@ -463,6 +495,13 @@ /* End PBXFileReference section */ /* Begin PBXFrameworksBuildPhase section */ + 5CFE492429264DF1000F2856 /* Frameworks */ = { + isa = PBXFrameworksBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + runOnlyForDeploymentPostprocessing = 0; + }; 9A11AACC266FD77F000C1C05 /* Frameworks */ = { isa = PBXFrameworksBuildPhase; buildActionMask = 2147483647; @@ -575,6 +614,17 @@ /* End PBXFrameworksBuildPhase section */ /* Begin PBXGroup section */ + 5CFE492829264DF1000F2856 /* Helper */ = { + isa = PBXGroup; + children = ( + 5CFE492929264DF1000F2856 /* main.swift */, + 5CFE493829265055000F2856 /* protocol.swift */, + 5CFE493A292650BD000F2856 /* Info.plist */, + 5CFE493B292650F8000F2856 /* Launchd.plist */, + ); + path = Helper; + sourceTree = ""; + }; 9A11AAD0266FD77F000C1C05 /* Bluetooth */ = { isa = PBXGroup; children = ( @@ -618,6 +668,7 @@ 9A2846F72666A9CC00EC1F6D /* Kit.framework */, 9A11AACF266FD77F000C1C05 /* Bluetooth.framework */, 9AAC5E2A280ACC120043D892 /* Tests.xctest */, + 5CFE492729264DF1000F2856 /* eu.exelban.Stats.SMC.Helper */, ); name = Products; sourceTree = ""; @@ -716,7 +767,9 @@ isa = PBXGroup; children = ( 9A2848012666AB2F00EC1F6D /* updater.sh */, + 5CFE494129265418000F2856 /* uninstall.sh */, 9A46BF35266D6E17001A1117 /* i18n.py */, + 5CFE494329265421000F2856 /* changelog.py */, ); path = scripts; sourceTree = ""; @@ -848,6 +901,7 @@ 9ADE6FD9265D032100D2FBA8 /* SMC */ = { isa = PBXGroup; children = ( + 5CFE492829264DF1000F2856 /* Helper */, 9ADE6FDA265D032100D2FBA8 /* main.swift */, 9ADE7038265D059000D2FBA8 /* smc.swift */, ); @@ -952,6 +1006,23 @@ /* End PBXHeadersBuildPhase section */ /* Begin PBXNativeTarget section */ + 5CFE492629264DF1000F2856 /* Helper */ = { + isa = PBXNativeTarget; + buildConfigurationList = 5CFE492D29264DF1000F2856 /* Build configuration list for PBXNativeTarget "Helper" */; + buildPhases = ( + 5CFE492329264DF1000F2856 /* Sources */, + 5CFE492429264DF1000F2856 /* Frameworks */, + 5CFE492529264DF1000F2856 /* CopyFiles */, + ); + buildRules = ( + ); + dependencies = ( + ); + name = Helper; + productName = Helper; + productReference = 5CFE492729264DF1000F2856 /* eu.exelban.Stats.SMC.Helper */; + productType = "com.apple.product-type.tool"; + }; 9A11AACE266FD77F000C1C05 /* Bluetooth */ = { isa = PBXNativeTarget; buildConfigurationList = 9A11AADA266FD77F000C1C05 /* Build configuration list for PBXNativeTarget "Bluetooth" */; @@ -983,6 +1054,7 @@ 9AECEF3D24ACF98800DB95D4 /* Copy Files */, 9A88E2672659002E00E2B7B0 /* ShellScript */, 9A46BF89266D7CFA001A1117 /* CopyFiles */, + 5CFE493C29265130000F2856 /* CopyFiles */, ); buildRules = ( ); @@ -1219,10 +1291,13 @@ KnownAssetTags = ( New, ); - LastSwiftUpdateCheck = 1240; - LastUpgradeCheck = 1400; + LastSwiftUpdateCheck = 1410; + LastUpgradeCheck = 1410; ORGANIZATIONNAME = "Serhiy Mytrovtsiy"; TargetAttributes = { + 5CFE492629264DF1000F2856 = { + CreatedOnToolsVersion = 14.1; + }; 9A11AACE266FD77F000C1C05 = { CreatedOnToolsVersion = 12.4; LastSwiftMigration = 1240; @@ -1340,6 +1415,7 @@ 9AE29AD4249A50350071B02D /* Sensors */, 9A11AACE266FD77F000C1C05 /* Bluetooth */, 9AAC5E29280ACC120043D892 /* Tests */, + 5CFE492629264DF1000F2856 /* Helper */, ); }; /* End PBXProject section */ @@ -1369,6 +1445,8 @@ 9A46BF36266D6E17001A1117 /* i18n.py in Resources */, 9A2848892666AC0100EC1F6D /* Assets.xcassets in Resources */, 9A2848082666AB3000EC1F6D /* updater.sh in Resources */, + 5CFE494229265418000F2856 /* uninstall.sh in Resources */, + 5CFE494429265421000F2856 /* changelog.py in Resources */, ); runOnlyForDeploymentPostprocessing = 0; }; @@ -1466,6 +1544,15 @@ /* End PBXShellScriptBuildPhase section */ /* Begin PBXSourcesBuildPhase section */ + 5CFE492329264DF1000F2856 /* Sources */ = { + isa = PBXSourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + 5CFE492A29264DF1000F2856 /* main.swift in Sources */, + 5CFE493929265055000F2856 /* protocol.swift in Sources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; 9A11AACB266FD77F000C1C05 /* Sources */ = { isa = PBXSourcesBuildPhase; buildActionMask = 2147483647; @@ -1495,6 +1582,7 @@ isa = PBXSourcesBuildPhase; buildActionMask = 2147483647; files = ( + 5C8E001029269C7F0027C75A /* protocol.swift in Sources */, 9AD7F866266F759200E5F863 /* smc.swift in Sources */, 9A2847612666AA2700EC1F6D /* PieChart.swift in Sources */, 9A2847672666AA2700EC1F6D /* BarChart.swift in Sources */, @@ -1770,6 +1858,58 @@ /* End PBXVariantGroup section */ /* Begin XCBuildConfiguration section */ + 5CFE492B29264DF1000F2856 /* Debug */ = { + isa = XCBuildConfiguration; + buildSettings = { + CLANG_CXX_LANGUAGE_STANDARD = "gnu++20"; + CODE_SIGN_IDENTITY = "-"; + CODE_SIGN_STYLE = Automatic; + DEVELOPMENT_TEAM = RP2S87B72W; + ENABLE_HARDENED_RUNTIME = YES; + INFOPLIST_FILE = "$(SRCROOT)/Helper/Info.plist"; + MACOSX_DEPLOYMENT_TARGET = 10.13; + "OTHER_LDFLAGS[arch=*]" = ( + "-sectcreate", + __TEXT, + __info_plist, + "\"$(SRCROOT)/SMC/Helper/Info.plist\"", + "-sectcreate", + __TEXT, + __launchd_plist, + "\"$(SRCROOT)/SMC/Helper/Launchd.plist\"", + ); + PRODUCT_NAME = eu.exelban.Stats.SMC.Helper; + SKIP_INSTALL = YES; + SWIFT_VERSION = 5.0; + }; + name = Debug; + }; + 5CFE492C29264DF1000F2856 /* Release */ = { + isa = XCBuildConfiguration; + buildSettings = { + CLANG_CXX_LANGUAGE_STANDARD = "gnu++20"; + CODE_SIGN_IDENTITY = "-"; + CODE_SIGN_STYLE = Automatic; + DEVELOPMENT_TEAM = RP2S87B72W; + ENABLE_HARDENED_RUNTIME = YES; + INFOPLIST_FILE = "$(SRCROOT)/Helper/Info.plist"; + MACOSX_DEPLOYMENT_TARGET = 10.13; + "OTHER_LDFLAGS[arch=*]" = ( + "-sectcreate", + __TEXT, + __info_plist, + "\"$(SRCROOT)/SMC/Helper/Info.plist\"", + "-sectcreate", + __TEXT, + __launchd_plist, + "\"$(SRCROOT)/SMC/Helper/Launchd.plist\"", + ); + PRODUCT_NAME = eu.exelban.Stats.SMC.Helper; + SKIP_INSTALL = YES; + SWIFT_VERSION = 5.0; + }; + name = Release; + }; 9A11AAD8266FD77F000C1C05 /* Debug */ = { isa = XCBuildConfiguration; buildSettings = { @@ -2431,7 +2571,7 @@ "@executable_path/../Frameworks", "@loader_path/../Frameworks", ); - MACOSX_DEPLOYMENT_TARGET = 10.15; + MACOSX_DEPLOYMENT_TARGET = 10.13; PRODUCT_BUNDLE_IDENTIFIER = io.serhiy.Stats.Tests; PRODUCT_NAME = "$(TARGET_NAME)"; SWIFT_VERSION = 5.0; @@ -2453,7 +2593,7 @@ "@executable_path/../Frameworks", "@loader_path/../Frameworks", ); - MACOSX_DEPLOYMENT_TARGET = 10.15; + MACOSX_DEPLOYMENT_TARGET = 10.13; PRODUCT_BUNDLE_IDENTIFIER = io.serhiy.Stats.Tests; PRODUCT_NAME = "$(TARGET_NAME)"; SWIFT_VERSION = 5.0; @@ -2701,6 +2841,15 @@ /* End XCBuildConfiguration section */ /* Begin XCConfigurationList section */ + 5CFE492D29264DF1000F2856 /* Build configuration list for PBXNativeTarget "Helper" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + 5CFE492B29264DF1000F2856 /* Debug */, + 5CFE492C29264DF1000F2856 /* Release */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; 9A11AADA266FD77F000C1C05 /* Build configuration list for PBXNativeTarget "Bluetooth" */ = { isa = XCConfigurationList; buildConfigurations = ( diff --git a/Stats.xcodeproj/xcshareddata/xcschemes/Stats.xcscheme b/Stats.xcodeproj/xcshareddata/xcschemes/Stats.xcscheme index 4de4f2f0..037f53a5 100644 --- a/Stats.xcodeproj/xcshareddata/xcschemes/Stats.xcscheme +++ b/Stats.xcodeproj/xcshareddata/xcschemes/Stats.xcscheme @@ -20,6 +20,20 @@ ReferencedContainer = "container:Stats.xcodeproj"> + + + + NSApplication NSUserNotificationAlertStyle alert + SMPrivilegedExecutables + + eu.exelban.Stats.SMC.Helper + identifier "eu.exelban.Stats.SMC.Helper" and anchor apple generic and certificate 1[field.1.2.840.113635.100.6.2.1] /* exists */ +