From ed6f2829b18a52b25f57d3317ab63ada1c6f7f86 Mon Sep 17 00:00:00 2001 From: "L. E. Segovia" <13498015+amyspark@users.noreply.github.com> Date: Tue, 4 Sep 2018 21:11:29 +0000 Subject: [PATCH] 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. --- Library/Homebrew/cask/cmd/doctor.rb | 18 +++++ Library/Homebrew/cask/installer.rb | 2 +- Library/Homebrew/cask/quarantine.rb | 70 ++++++++++++++------ Library/Homebrew/cask/utils/quarantine.swift | 61 +++++++++-------- 4 files changed, 102 insertions(+), 49 deletions(-) diff --git a/Library/Homebrew/cask/cmd/doctor.rb b/Library/Homebrew/cask/cmd/doctor.rb index 8772712282..c0886c9fd1 100644 --- a/Library/Homebrew/cask/cmd/doctor.rb +++ b/Library/Homebrew/cask/cmd/doctor.rb @@ -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 diff --git a/Library/Homebrew/cask/installer.rb b/Library/Homebrew/cask/installer.rb index a029984c57..ad43f82b64 100644 --- a/Library/Homebrew/cask/installer.rb +++ b/Library/Homebrew/cask/installer.rb @@ -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 diff --git a/Library/Homebrew/cask/quarantine.rb b/Library/Homebrew/cask/quarantine.rb index c55a93e6a8..48ace13b94 100644 --- a/Library/Homebrew/cask/quarantine.rb +++ b/Library/Homebrew/cask/quarantine.rb @@ -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? diff --git a/Library/Homebrew/cask/utils/quarantine.swift b/Library/Homebrew/cask/utils/quarantine.swift index e20889434c..603393589f 100644 --- a/Library/Homebrew/cask/utils/quarantine.swift +++ b/Library/Homebrew/cask/utils/quarantine.swift @@ -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)