feat: moved from the AppleScript for asking a root access when manipulating the fans to the Helper (SMJobBless + XPC) (#1173)

This commit is contained in:
Serhiy Mytrovtsiy
2022-11-18 22:51:34 +01:00
parent ed737fe0b4
commit e9bc4cc5d3
12 changed files with 443 additions and 64 deletions

View File

@@ -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<AuthorizationItem>.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<CFError>?
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
}
}

5
Kit/scripts/uninstall.sh Normal file
View File

@@ -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

View File

@@ -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 {

View File

@@ -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

18
SMC/Helper/Info.plist Normal file
View File

@@ -0,0 +1,18 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>CFBundleIdentifier</key>
<string>eu.exelban.Stats.SMC.Helper</string>
<key>CFBundleName</key>
<string>eu.exelban.Stats.SMC.Helper</string>
<key>CFBundleShortVersionString</key>
<string>1.0</string>
<key>CFBundleVersion</key>
<string>1</string>
<key>SMAuthorizedClients</key>
<array>
<string>identifier &quot;eu.exelban.Stats&quot; and anchor apple generic and certificate 1[field.1.2.840.113635.100.6.2.1] /* exists */</string>
</array>
</dict>
</plist>

13
SMC/Helper/Launchd.plist Normal file
View File

@@ -0,0 +1,13 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>Label</key>
<string>eu.exelban.Stats.SMC.Helper</string>
<key>MachServices</key>
<dict>
<key>eu.exelban.Stats.SMC.Helper</key>
<true/>
</dict>
</dict>
</plist>

97
SMC/Helper/main.swift Normal file
View File

@@ -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)!
}
}

20
SMC/Helper/protocol.swift Normal file
View File

@@ -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)
}

View File

@@ -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")

View File

@@ -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 = "<group>"; };
40BE2B202745D63800AE9396 /* da */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = da; path = da.lproj/Localizable.strings; sourceTree = "<group>"; };
4921436D25319699000A1C47 /* ko */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = ko; path = ko.lproj/Localizable.strings; sourceTree = "<group>"; };
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 = "<group>"; };
5CFE493829265055000F2856 /* protocol.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = protocol.swift; sourceTree = "<group>"; };
5CFE493A292650BD000F2856 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = "<group>"; };
5CFE493B292650F8000F2856 /* Launchd.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Launchd.plist; sourceTree = "<group>"; };
5CFE494129265418000F2856 /* uninstall.sh */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.script.sh; path = uninstall.sh; sourceTree = "<group>"; };
5CFE494329265421000F2856 /* changelog.py */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.script.python; path = changelog.py; sourceTree = "<group>"; };
62BA5F74254810C8009D0AC2 /* es */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = es; path = es.lproj/Localizable.strings; sourceTree = "<group>"; };
63A07F97275018DF00352C46 /* ca */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = ca; path = ca.lproj/Localizable.strings; sourceTree = "<group>"; };
7A19DAE52552C326001B192F /* fr */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = fr; path = fr.lproj/Localizable.strings; sourceTree = "<group>"; };
@@ -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 = "<group>";
};
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 = "<group>";
@@ -716,7 +767,9 @@
isa = PBXGroup;
children = (
9A2848012666AB2F00EC1F6D /* updater.sh */,
5CFE494129265418000F2856 /* uninstall.sh */,
9A46BF35266D6E17001A1117 /* i18n.py */,
5CFE494329265421000F2856 /* changelog.py */,
);
path = scripts;
sourceTree = "<group>";
@@ -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 = (

View File

@@ -20,6 +20,20 @@
ReferencedContainer = "container:Stats.xcodeproj">
</BuildableReference>
</BuildActionEntry>
<BuildActionEntry
buildForTesting = "YES"
buildForRunning = "YES"
buildForProfiling = "YES"
buildForArchiving = "YES"
buildForAnalyzing = "YES">
<BuildableReference
BuildableIdentifier = "primary"
BlueprintIdentifier = "5CFE492629264DF1000F2856"
BuildableName = "eu.exelban.Stats.SMC.Helper"
BlueprintName = "Helper"
ReferencedContainer = "container:Stats.xcodeproj">
</BuildableReference>
</BuildActionEntry>
</BuildActionEntries>
</BuildAction>
<TestAction

View File

@@ -39,5 +39,10 @@
<string>NSApplication</string>
<key>NSUserNotificationAlertStyle</key>
<string>alert</string>
<key>SMPrivilegedExecutables</key>
<dict>
<key>eu.exelban.Stats.SMC.Helper</key>
<string>identifier &quot;eu.exelban.Stats.SMC.Helper&quot; and anchor apple generic and certificate 1[field.1.2.840.113635.100.6.2.1] /* exists */</string>
</dict>
</dict>
</plist>