brew/Library/Homebrew/cask/quarantine.rb

169 lines
4.9 KiB
Ruby
Raw Normal View History

# frozen_string_literal: true
require "development_tools"
2018-09-06 08:29:14 +02:00
module Cask
module Quarantine
module_function
QUARANTINE_ATTRIBUTE = "com.apple.quarantine"
QUARANTINE_SCRIPT = (HOMEBREW_LIBRARY_PATH/"cask/utils/quarantine.swift").freeze
# @private
def swift
@swift ||= DevelopmentTools.locate("swift")
end
# @private
def xattr
@xattr ||= DevelopmentTools.locate("xattr")
end
def check_quarantine_support
odebug "Checking quarantine support"
if !system_command(xattr, print_stderr: false).success?
odebug "There's not a working version of xattr."
:xattr_broken
elsif swift.nil?
odebug "Swift is not available on this system."
:no_swift
else
api_check = system_command(swift,
2018-11-02 17:18:07 +00:00
args: [QUARANTINE_SCRIPT],
print_stderr: false)
case api_check.exit_status
when 5
odebug "This feature requires the macOS 10.10 SDK or higher."
:no_quarantine
when 2
odebug "Quarantine is available."
:quarantine_available
else
odebug "Unknown support status"
:unknown
end
end
end
def available?
@status ||= check_quarantine_support
@status == :quarantine_available
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
def status(file)
system_command(xattr,
args: ["-p", QUARANTINE_ATTRIBUTE, file],
print_stderr: false).stdout.rstrip
end
def toggle_no_translocation_bit(attribute)
fields = attribute.split(";")
# Fields: status, epoch, download agent, event ID
# Let's toggle the app translocation bit, bit 8
2018-10-03 21:03:22 +00:00
# http://www.openradar.me/radar?id=5022734169931776
fields[0] = (fields[0].to_i(16) | 0x0100).to_s(16).rjust(4, "0")
fields.join(";")
end
def release!(download_path: nil)
return unless detect(download_path)
odebug "Releasing #{download_path} from quarantine"
quarantiner = system_command(xattr,
2018-11-02 17:18:07 +00:00
args: [
"-d",
QUARANTINE_ATTRIBUTE,
download_path,
],
print_stderr: false)
return if quarantiner.success?
raise CaskQuarantineReleaseError.new(download_path, quarantiner.stderr)
end
def cask!(cask: nil, download_path: nil, action: true)
return if cask.nil? || download_path.nil?
return if detect(download_path)
odebug "Quarantining #{download_path}"
quarantiner = system_command(swift,
2018-11-02 17:18:07 +00:00
args: [
QUARANTINE_SCRIPT,
download_path,
cask.url.to_s,
cask.homepage.to_s,
],
print_stderr: false)
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
end
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 = toggle_no_translocation_bit(status(from))
resolved_paths = Pathname.glob(to/"**/*", File::FNM_DOTMATCH).select(&:exist?)
system_command!("/usr/bin/xargs",
2018-11-02 17:18:07 +00:00
args: [
"-0",
"--",
"/bin/chmod",
"-h",
"u+w",
],
2018-10-08 18:23:21 +00:00
input: resolved_paths.join("\0"))
quarantiner = system_command("/usr/bin/xargs",
2018-11-02 17:18:07 +00:00
args: [
"-0",
"--",
xattr,
"-w",
QUARANTINE_ATTRIBUTE,
quarantine_status,
],
2018-11-02 17:18:07 +00:00
input: resolved_paths.join("\0"),
print_stderr: false)
return if quarantiner.success?
raise CaskQuarantinePropagationError.new(to, quarantiner.stderr)
end
end
end