2018-08-31 13:16:11 +00:00
|
|
|
require "development_tools"
|
2018-09-06 08:29:14 +02:00
|
|
|
module Cask
|
2018-08-31 13:16:11 +00:00
|
|
|
module Quarantine
|
|
|
|
module_function
|
|
|
|
|
|
|
|
QUARANTINE_ATTRIBUTE = "com.apple.quarantine".freeze
|
|
|
|
|
2018-09-03 19:39:07 +01:00
|
|
|
QUARANTINE_SCRIPT = (HOMEBREW_LIBRARY_PATH/"cask/utils/quarantine.swift").freeze
|
2018-08-31 13:16:11 +00:00
|
|
|
|
|
|
|
# @private
|
|
|
|
def swift
|
|
|
|
@swift ||= DevelopmentTools.locate("swift")
|
|
|
|
end
|
|
|
|
|
2018-09-04 21:11:29 +00:00
|
|
|
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
|
|
|
|
|
2018-08-31 13:16:11 +00:00
|
|
|
def available?
|
2018-09-04 21:11:29 +00:00
|
|
|
@status ||= check_quarantine_support
|
|
|
|
|
|
|
|
@status == :quarantine_available
|
2018-08-31 13:16:11 +00:00
|
|
|
end
|
|
|
|
|
|
|
|
def detect(file)
|
|
|
|
return if file.nil?
|
|
|
|
|
|
|
|
odebug "Verifying Gatekeeper status of #{file}"
|
|
|
|
|
|
|
|
quarantine_status = !status(file).empty?
|
|
|
|
|
|
|
|
odebug "#{file} is #{quarantine_status ? "quarantined" : "not quarantined"}"
|
|
|
|
|
|
|
|
quarantine_status
|
|
|
|
end
|
|
|
|
|
2018-09-04 21:11:29 +00:00
|
|
|
def status(file)
|
|
|
|
system_command("/usr/bin/xattr",
|
|
|
|
args: ["-p", QUARANTINE_ATTRIBUTE, file],
|
|
|
|
print_stderr: false).stdout.rstrip
|
2018-08-31 13:16:11 +00:00
|
|
|
end
|
|
|
|
|
2018-09-07 15:37:31 +00:00
|
|
|
def disable_translocation!(xattr)
|
|
|
|
fields = xattr.split(";")
|
|
|
|
|
|
|
|
# Fields: status, epoch, download agent, event ID
|
|
|
|
# Let's toggle the app translocation bit, bit 8
|
|
|
|
# http://openradar.me/radar?id=5022734169931776
|
|
|
|
|
|
|
|
fields[0] = (fields[0].to_i(16) | 0x0100).to_s(16).rjust(4, "0")
|
|
|
|
|
|
|
|
fields.join(";")
|
|
|
|
end
|
|
|
|
|
|
|
|
def cask!(cask: nil, download_path: nil, action: true)
|
2018-08-31 13:16:11 +00:00
|
|
|
return if cask.nil? || download_path.nil?
|
|
|
|
|
2018-09-07 15:37:31 +00:00
|
|
|
if action
|
|
|
|
return if detect(download_path)
|
2018-08-31 13:16:11 +00:00
|
|
|
|
2018-09-07 15:37:31 +00:00
|
|
|
odebug "Quarantining #{download_path}"
|
2018-08-31 13:16:11 +00:00
|
|
|
|
2018-09-07 15:37:31 +00:00
|
|
|
quarantiner = system_command(swift,
|
|
|
|
args: [
|
|
|
|
QUARANTINE_SCRIPT,
|
|
|
|
download_path,
|
|
|
|
cask.url.to_s,
|
|
|
|
cask.homepage.to_s,
|
|
|
|
])
|
2018-08-31 13:16:11 +00:00
|
|
|
|
2018-09-07 15:37:31 +00:00
|
|
|
return if quarantiner.success?
|
|
|
|
|
|
|
|
case quarantiner.exit_status
|
|
|
|
when 2
|
|
|
|
raise CaskQuarantineError.new(download_path, "Insufficient parameters")
|
|
|
|
else
|
|
|
|
raise CaskQuarantineError.new(download_path, quarantiner.stderr)
|
|
|
|
end
|
2018-08-31 13:16:11 +00:00
|
|
|
else
|
2018-09-07 15:37:31 +00:00
|
|
|
return unless detect(download_path)
|
|
|
|
|
|
|
|
odebug "Releasing #{download_path} from quarantine"
|
|
|
|
|
|
|
|
quarantiner = system_command("/usr/bin/xattr",
|
|
|
|
args: [
|
|
|
|
"-d",
|
|
|
|
QUARANTINE_ATTRIBUTE,
|
|
|
|
download_path,
|
|
|
|
],
|
|
|
|
print_stderr: false)
|
|
|
|
|
|
|
|
return if quarantiner.success?
|
|
|
|
|
|
|
|
raise CaskQuarantineReleaseError.new(download_path, quarantiner.stderr)
|
2018-08-31 13:16:11 +00:00
|
|
|
end
|
|
|
|
end
|
|
|
|
|
2018-09-04 21:11:29 +00:00
|
|
|
def propagate(from: nil, to: nil)
|
2018-08-31 13:16:11 +00:00
|
|
|
return if from.nil? || to.nil?
|
|
|
|
|
|
|
|
raise CaskError, "#{from} was not quarantined properly." unless detect(from)
|
|
|
|
|
|
|
|
odebug "Propagating quarantine from #{from} to #{to}"
|
|
|
|
|
2018-09-07 15:37:31 +00:00
|
|
|
quarantine_status = disable_translocation!(status(from))
|
2018-09-04 21:11:29 +00:00
|
|
|
|
|
|
|
resolved_paths = Pathname.glob(to/"**/*", File::FNM_DOTMATCH)
|
|
|
|
|
2018-09-07 16:57:00 +00:00
|
|
|
system_command!("/bin/chmod", args: ["-R", "u+w", to])
|
2018-09-07 15:37:31 +00:00
|
|
|
|
2018-09-04 21:11:29 +00:00
|
|
|
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)
|
2018-08-31 13:16:11 +00:00
|
|
|
|
|
|
|
return if quarantiner.success?
|
|
|
|
|
|
|
|
raise CaskQuarantinePropagationError.new(to, quarantiner.stderr)
|
|
|
|
end
|
|
|
|
end
|
|
|
|
end
|