【问题标题】:How to delete system domain file(s) on OS X using Swift 2?如何使用 Swift 2 在 OS X 上删除系统域文件?
【发布时间】:2016-04-30 17:14:13
【问题描述】:

对于一个开源项目,我们想要创建一个 OS X 卸载程序,它应该能够删除 usersystem domain 文件。目标是仅在 Swift 中编写卸载程序。

在我的研究中,我发现了使用NSTask 发送rm 命令的示例, 或其他人建议使用SMJobBlessHelperTool 进行身份验证。对我来说,两者似乎都不是正确的方法。我是 OS X 开发的新手,所以我很难说哪种方法是完成任务的正确方法。

我正在寻找 Swift 2 中的示例,它允许用户验证和删除 usersystem domain 文件。如果有任何人帮助我,我将不胜感激。

【问题讨论】:

  • 我建议Authorization Service Programming Guide。另外,请注意 El Capitan 的无 root 模式:即使用户允许您进行 root 访问,您也无法删除某些系统文件
  • 谢谢,我会阅读指南并尝试一下。仍然欢迎任何实际示例。

标签: swift macos swift2


【解决方案1】:

在玩了几个小时 SecurityFoundation 之后,我发现它对我的口味来说太复杂了。另外,文档已经过时。灵感来自this question。你可以通过 AppleScript 来完成。

您需要将卸载程序分为两部分:一个默认目标 删除用户文件和一个 helper 删除系统文件(当然具有升级权限)。


选项 1

您可以将该帮助程序编写为 shell 脚本并将其作为资源包含:

文件delete_system_file.sh

#!/bin/bash
rm -f /usr/local/dummy.txt

在您的应用中:

let helper = NSBundle.mainBundle().pathForResource("delete_system_file", ofType: "sh")!
let script = "do shell script \"\(helper)\" with administrator privileges"

if let appleScript = NSAppleScript(source: script) {
    var error: NSDictionary? = nil

    appleScript.executeAndReturnError(&error)
    if error != nil {
        print(error!)
    } else {
        print("Deleted /usr/local/dummy.txt")
    }
} else {
    print("Cannot create the AppleScript object")
}

选项 2

您可以通过在项目中添加新目标来完全在 Swift 中完成此操作。假设您的第一个目标称为MyUninstaller

添加新目标

  1. 点击File > New > Target...
  2. 在 OS X 下,选择Application > Command Line Tool
  3. 给你的新目标起个名字,比如DeleteSystemFile

在左侧的 Project Navigator 中,展开 DeleteSystemFile 组并单击 main.swift 文件。删除dummy.txt 文件:

do {
    try NSFileManager.defaultManager().removeItemAtPath("/usr/local/dummy.txt")
} catch {
    print(error)
}

回到第一个目标

现在回到第一个目标 (MyUninstaller) 并添加 DeleteSystemFile 作为目标依赖项。

您可以通过 AppleScript 调用以提升权限运行第二个目标:

let helper = NSBundle.mainBundle().pathForAuxiliaryExecutable("DeleteSystemFile")!
let script = "do shell script \"\(helper)\" with administrator privileges"

if let appleScript = NSAppleScript(source: script) {
    var error: NSDictionary? = nil

    appleScript.executeAndReturnError(&error)
    if error != nil {
        print(error!)
    } else {
        print("Deleted /usr/local/dummy.txt")
    }
} else {
    print("Cannot create the AppleScript object")
}

选项 3

使用SMJobBless,这是苹果推荐的特权助手运行方式:

import SecurityFoundation
import ServiceManagement

// 1. Obtain an Authorization Reference
// You can do this at the beginning of the app. It has no extra rights until later
var authRef: AuthorizationRef = nil

let status = AuthorizationCreate(nil, nil, [.Defaults], &authRef)

// There's really no reason for this to fail, but we should check or completeness
guard status == errAuthorizationSuccess else {
    fatalError("Cannot create AuthorizationRef: \(status)")
}

// 2. Ask user for admin privilege
var authItem = AuthorizationItem(name: kSMRightBlessPrivilegedHelper, valueLength: 0, value: nil, flags: 0)
var authRights = AuthorizationRights(count: 1, items: &authItem)
let flags: AuthorizationFlags = [.Defaults, .InteractionAllowed, .ExtendRights]

let status2 = AuthorizationCopyRights(authRef, &authRights, nil, flags, nil)
if status2 != errAuthorizationSuccess {
    // Can't obtain admin privilege, handle error
    print("Cannot obtain admin privilege")
}

// 3. Run the privileged helper
// This label must be globally unique and matches the product name of your helper
let label = "com.myCompany.myApp.myAppPrivilgedHelper"
var error: CFError? = nil

let result = withUnsafeMutablePointer(&error) {
    SMJobBless(kSMDomainSystemLaunchd, label, authRef, UnsafeMutablePointer($0))
}

if !result {
    print(error!)
}

// 4. Release the Authorization Reference
AuthorizationFree(authRef, [.Defaults])

这涉及到一些设置,您可以在SMJobBless 的文档中了解这些设置。还有一个sample project in ObjC

免责声明:由于我没有个人签名密钥,因此无法全程测试。我可以从上面删除第 2 节,但为了完整起见将其包含在此处——示例项目就是这样做的。

【讨论】:

  • 感谢您的努力!我已经成功地测试过这种方法,但忘记提及它。对此感到抱歉。我的合作开发者提到在签名的应用程序中使用这种方法可能会有一些限制。我们还想创建一个“自定义卸载程序”,以便用户可以选择他想要卸载的组件。我更多地考虑使用AuthorizationRights / AuthorizationCopyRightsNSFileManager 来删除文件。你知道这是否可能吗?
  • 如果你有一个签名证书,你可以使用SMJobBless,这是苹果的幸运方式。请参阅我编辑的答案中的选项 3。
猜你喜欢
  • 2016-08-14
  • 2018-05-20
  • 1970-01-01
  • 1970-01-01
  • 2017-08-20
  • 1970-01-01
  • 2015-06-30
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多