- 菜单栏八种风格整体套用、可按指标单独指定,网速三种样式,悬停显示完整读数,字号缩小并统一 - 面板浅色、深色实色主题与一键切换,液态玻璃改为可选 - 修复关闭液态玻璃后面板内容尺寸翻倍导致看起来打不开,首次打开时高度偏小 - Developer ID 自动签名,辅助工具按自身签名团队校验调用方,新增发布脚本 - 更新日志、README、截图同步
61 lines
3.0 KiB
Swift
61 lines
3.0 KiB
Swift
import Foundation
|
||
import Security
|
||
|
||
public enum HelperConstants {
|
||
public static let machServiceName = "com.openstats.helper"
|
||
public static let launchdPlistName = "com.openstats.helper.plist"
|
||
public static let appBundleIdentifier = "com.openstats.app"
|
||
/// 与 App 版本同步;App 发现辅助工具版本不一致时提示重新安装
|
||
public static let protocolVersion = 2
|
||
|
||
/// 辅助工具对调用方的签名要求:与辅助工具自身同一团队签名的 OpenStats。
|
||
/// ad-hoc 签名的开发构建没有团队,只能校验 bundle identifier。
|
||
public static func clientRequirement(teamIdentifier: String?) -> String {
|
||
let identifier = "identifier \"\(appBundleIdentifier)\""
|
||
guard let teamIdentifier, !teamIdentifier.isEmpty else { return identifier }
|
||
return identifier + " and anchor apple generic and certificate leaf[subject.OU] = \"\(teamIdentifier)\""
|
||
}
|
||
}
|
||
|
||
public enum CodeSigningInfo {
|
||
/// 当前进程签名所属的 Team ID;ad-hoc 签名时为 nil
|
||
public static func currentTeamIdentifier() -> String? {
|
||
var code: SecCode?
|
||
guard SecCodeCopySelf([], &code) == errSecSuccess, let code else { return nil }
|
||
var staticCode: SecStaticCode?
|
||
guard SecCodeCopyStaticCode(code, [], &staticCode) == errSecSuccess, let staticCode else { return nil }
|
||
var information: CFDictionary?
|
||
guard SecCodeCopySigningInformation(staticCode, SecCSFlags(rawValue: kSecCSSigningInformation), &information) == errSecSuccess,
|
||
let dictionary = information as? [String: Any] else { return nil }
|
||
return dictionary[kSecCodeInfoTeamIdentifier as String] as? String
|
||
}
|
||
}
|
||
|
||
/// 辅助工具以 root 运行,只暴露固定的少量操作,不提供任意命令执行能力。
|
||
/// 所有回调中的 `String?` 为错误描述,nil 表示成功。
|
||
@objc public protocol OpenStatsHelperProtocol {
|
||
func protocolVersion(reply: @escaping @Sendable (Int) -> Void)
|
||
func setFanTarget(fan: Int, rpm: Double, reply: @escaping @Sendable (String?) -> Void)
|
||
func setFanAutomatic(fan: Int, reply: @escaping @Sendable (String?) -> Void)
|
||
func resetAllFans(reply: @escaping @Sendable (String?) -> Void)
|
||
func setSleepDisabled(_ disabled: Bool, reply: @escaping @Sendable (String?) -> Void)
|
||
func flushDNSCache(reply: @escaping @Sendable (String?) -> Void)
|
||
func purgeMemory(reply: @escaping @Sendable (String?) -> Void)
|
||
}
|
||
|
||
/// 需要管理员权限的系统维护命令。辅助工具与未安装辅助工具时的授权回退共用同一份固定命令
|
||
public enum MaintenanceCommand: String, Sendable, CaseIterable {
|
||
case flushDNS, purgeMemory
|
||
|
||
public var steps: [(path: String, arguments: [String])] {
|
||
switch self {
|
||
case .flushDNS: [("/usr/bin/dscacheutil", ["-flushcache"]), ("/usr/bin/killall", ["-HUP", "mDNSResponder"])]
|
||
case .purgeMemory: [("/usr/sbin/purge", [])]
|
||
}
|
||
}
|
||
|
||
public var shellCommand: String {
|
||
steps.map { ([$0.path] + $0.arguments).joined(separator: " ") }.joined(separator: "; ")
|
||
}
|
||
}
|