Cask: check support of quarantine's tools

- In some cases (usually old CLT versions) Swift is available but needs an
extra guard to use the quarantine API.
- xattr's native filesystem recursion is an Apple extension which is
not available in Mojave; so let's use xargs.
- Insert a quarantine support check in brew cask doctor.

Fixes Homebrew/homebrew-cask#51554, and fixes Homebrew/homebrew-cask#51538.
This commit is contained in:
L. E. Segovia 2018-09-04 21:11:29 +00:00
parent 817b72d5ba
commit ed6f2829b1
No known key found for this signature in database
GPG Key ID: D5D1DC48B52B7AD5
4 changed files with 102 additions and 49 deletions

View File

@ -22,6 +22,7 @@ module Hbc
def run
check_software_versions
check_quarantine_support
check_install_location
check_staging_location
check_taps
@ -116,6 +117,23 @@ module Hbc
(locale_variables + environment_variables).sort.each(&method(:render_env_var))
end
def check_quarantine_support
ohai "Gatekeeper support"
status = Quarantine.check_quarantine_support
case status
when :quarantine_available
puts "Enabled"
when :no_swift
add_error "Swift is not available on this system."
when :no_quarantine
add_error "This feature requires the macOS 10.10 SDK or higher."
else
onoe "Unknown support status"
end
end
def user_tilde(path)
self.class.user_tilde(path)
end

View File

@ -186,7 +186,7 @@ module Hbc
return unless quarantine?
return unless Quarantine.available?
Quarantine.propagate(from: @downloaded_path, to: @cask.staged_path, command: @command)
Quarantine.propagate(from: @downloaded_path, to: @cask.staged_path)
end
def install_artifacts

View File

@ -12,10 +12,29 @@ module Hbc
@swift ||= DevelopmentTools.locate("swift")
end
def check_quarantine_support
odebug "Checking quarantine support"
if swift.nil?
odebug "Swift is not available on this system."
return :no_swift
end
api_check = system_command(swift, args: [QUARANTINE_SCRIPT])
if api_check.exit_status == 5
odebug "This feature requires the macOS 10.10 SDK or higher."
return :no_quarantine
end
odebug "Quarantine is available."
:quarantine_available
end
def available?
status = !swift.nil?
odebug "Quarantine is #{status ? "available" : "not available"}."
status
@status ||= check_quarantine_support
@status == :quarantine_available
end
def detect(file)
@ -30,24 +49,24 @@ module Hbc
quarantine_status
end
def status(file, command: SystemCommand)
command.run("/usr/bin/xattr",
args: ["-p", QUARANTINE_ATTRIBUTE, file],
print_stderr: false).stdout.rstrip
def status(file)
system_command("/usr/bin/xattr",
args: ["-p", QUARANTINE_ATTRIBUTE, file],
print_stderr: false).stdout.rstrip
end
def cask(cask: nil, download_path: nil, command: SystemCommand)
def cask(cask: nil, download_path: nil)
return if cask.nil? || download_path.nil?
odebug "Quarantining #{download_path}"
quarantiner = command.run(swift,
args: [
QUARANTINE_SCRIPT,
download_path,
cask.url.to_s,
cask.homepage.to_s,
])
quarantiner = system_command(swift,
args: [
QUARANTINE_SCRIPT,
download_path,
cask.url.to_s,
cask.homepage.to_s,
])
return if quarantiner.success?
@ -59,18 +78,29 @@ module Hbc
end
end
def propagate(from: nil, to: nil, command: SystemCommand)
def propagate(from: nil, to: nil)
return if from.nil? || to.nil?
raise CaskError, "#{from} was not quarantined properly." unless detect(from)
odebug "Propagating quarantine from #{from} to #{to}"
quarantine_status = status(from, command: command)
quarantine_status = status(from)
quarantiner = command.run("/usr/bin/xattr",
args: ["-w", "-rs", QUARANTINE_ATTRIBUTE, quarantine_status, to],
print_stderr: false)
resolved_paths = Pathname.glob(to/"**/*", File::FNM_DOTMATCH)
quarantiner = system_command("/usr/bin/xargs",
args: [
"-0",
"--",
"/usr/bin/xattr",
"-w",
"-s",
QUARANTINE_ATTRIBUTE,
quarantine_status,
],
input: resolved_paths.join("\0"),
print_stderr: false)
return if quarantiner.success?

View File

@ -7,36 +7,41 @@ struct swifterr: TextOutputStream {
mutating func write(_ string: String) { fputs(string, stderr) }
}
if (CommandLine.arguments.count < 4) {
exit(2)
}
let dataLocationUrl: NSURL = NSURL.init(fileURLWithPath: CommandLine.arguments[1])
var errorBag: NSError?
let quarantineProperties: [String: Any] = [
kLSQuarantineAgentNameKey as String: "Homebrew Cask",
kLSQuarantineTypeKey as String: kLSQuarantineTypeWebDownload,
kLSQuarantineDataURLKey as String: CommandLine.arguments[2],
kLSQuarantineOriginURLKey as String: CommandLine.arguments[3]
]
if (dataLocationUrl.checkResourceIsReachableAndReturnError(&errorBag)) {
do {
try dataLocationUrl.setResourceValue(
quarantineProperties as NSDictionary,
forKey: URLResourceKey.quarantinePropertiesKey
)
if #available(macOS 10.10, *) {
if (CommandLine.arguments.count < 4) {
exit(2)
}
catch {
print(error.localizedDescription, to: &swifterr.stream)
exit(1)
let dataLocationUrl: NSURL = NSURL.init(fileURLWithPath: CommandLine.arguments[1])
var errorBag: NSError?
let quarantineProperties: [String: Any] = [
kLSQuarantineAgentNameKey as String: "Homebrew Cask",
kLSQuarantineTypeKey as String: kLSQuarantineTypeWebDownload,
kLSQuarantineDataURLKey as String: CommandLine.arguments[2],
kLSQuarantineOriginURLKey as String: CommandLine.arguments[3]
]
if (dataLocationUrl.checkResourceIsReachableAndReturnError(&errorBag)) {
do {
try dataLocationUrl.setResourceValue(
quarantineProperties as NSDictionary,
forKey: URLResourceKey.quarantinePropertiesKey
)
}
catch {
print(error.localizedDescription, to: &swifterr.stream)
exit(1)
}
}
else {
print(errorBag!.localizedDescription, to: &swifterr.stream)
exit(3)
}
exit(0)
}
else {
print(errorBag!.localizedDescription, to: &swifterr.stream)
exit(3)
exit(5)
}
exit(0)