2020-10-10 14:16:11 +02:00
|
|
|
# typed: false
|
2019-04-19 15:38:03 +09:00
|
|
|
# frozen_string_literal: true
|
|
|
|
|
2018-08-31 13:16:11 +00:00
|
|
|
require "development_tools"
|
2020-08-09 01:34:07 +02:00
|
|
|
require "cask/exceptions"
|
|
|
|
|
2018-09-06 08:29:14 +02:00
|
|
|
module Cask
|
2020-08-24 23:44:12 +02:00
|
|
|
# Helper module for quarantining files.
|
|
|
|
#
|
|
|
|
# @api private
|
2018-08-31 13:16:11 +00:00
|
|
|
module Quarantine
|
2020-10-20 12:03:48 +02:00
|
|
|
extend T::Sig
|
|
|
|
|
2018-08-31 13:16:11 +00:00
|
|
|
module_function
|
|
|
|
|
2019-04-19 15:38:03 +09:00
|
|
|
QUARANTINE_ATTRIBUTE = "com.apple.quarantine"
|
2018-08-31 13:16:11 +00:00
|
|
|
|
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
|
|
|
|
|
|
|
def swift
|
|
|
|
@swift ||= DevelopmentTools.locate("swift")
|
|
|
|
end
|
2020-08-24 23:44:12 +02:00
|
|
|
private :swift
|
2018-08-31 13:16:11 +00:00
|
|
|
|
2018-09-26 20:55:54 +00:00
|
|
|
def xattr
|
|
|
|
@xattr ||= DevelopmentTools.locate("xattr")
|
|
|
|
end
|
2020-08-24 23:44:12 +02:00
|
|
|
private :xattr
|
2018-09-26 20:55:54 +00:00
|
|
|
|
2020-10-20 12:03:48 +02:00
|
|
|
sig { returns(Symbol) }
|
2018-09-04 21:11:29 +00:00
|
|
|
def check_quarantine_support
|
|
|
|
odebug "Checking quarantine support"
|
|
|
|
|
2021-07-19 10:02:19 +08:00
|
|
|
if !system_command(xattr, args: ["-h"], print_stderr: false).success?
|
2021-01-24 21:40:41 -05:00
|
|
|
odebug "There's no working version of `xattr` on this system."
|
2018-09-26 20:55:54 +00:00
|
|
|
:xattr_broken
|
|
|
|
elsif swift.nil?
|
2018-09-04 21:11:29 +00:00
|
|
|
odebug "Swift is not available on this system."
|
2018-09-14 15:48:16 +00:00
|
|
|
:no_swift
|
|
|
|
else
|
|
|
|
api_check = system_command(swift,
|
2018-11-02 17:18:07 +00:00
|
|
|
args: [QUARANTINE_SCRIPT],
|
2018-09-14 15:48:16 +00:00
|
|
|
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
|
2018-09-04 21:11:29 +00:00
|
|
|
end
|
|
|
|
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)
|
2018-09-26 20:55:54 +00:00
|
|
|
system_command(xattr,
|
2018-09-04 21:11:29 +00:00
|
|
|
args: ["-p", QUARANTINE_ATTRIBUTE, file],
|
|
|
|
print_stderr: false).stdout.rstrip
|
2018-08-31 13:16:11 +00:00
|
|
|
end
|
|
|
|
|
2018-09-26 20:55:54 +00:00
|
|
|
def toggle_no_translocation_bit(attribute)
|
|
|
|
fields = attribute.split(";")
|
2018-09-07 15:37:31 +00:00
|
|
|
|
|
|
|
# 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
|
2018-09-07 15:37:31 +00:00
|
|
|
|
|
|
|
fields[0] = (fields[0].to_i(16) | 0x0100).to_s(16).rjust(4, "0")
|
|
|
|
|
|
|
|
fields.join(";")
|
|
|
|
end
|
|
|
|
|
2018-09-08 14:00:44 +00:00
|
|
|
def release!(download_path: nil)
|
|
|
|
return unless detect(download_path)
|
2018-08-31 13:16:11 +00:00
|
|
|
|
2018-09-08 14:00:44 +00:00
|
|
|
odebug "Releasing #{download_path} from quarantine"
|
2018-08-31 13:16:11 +00:00
|
|
|
|
2018-09-26 20:55:54 +00:00
|
|
|
quarantiner = system_command(xattr,
|
2018-11-02 17:18:07 +00:00
|
|
|
args: [
|
2018-09-14 15:48:16 +00:00
|
|
|
"-d",
|
|
|
|
QUARANTINE_ATTRIBUTE,
|
|
|
|
download_path,
|
|
|
|
],
|
|
|
|
print_stderr: false)
|
2018-08-31 13:16:11 +00:00
|
|
|
|
2018-09-08 14:00:44 +00:00
|
|
|
return if quarantiner.success?
|
2018-08-31 13:16:11 +00:00
|
|
|
|
2018-09-08 14:00:44 +00:00
|
|
|
raise CaskQuarantineReleaseError.new(download_path, quarantiner.stderr)
|
|
|
|
end
|
2018-09-07 15:37:31 +00:00
|
|
|
|
2018-09-08 14:00:44 +00:00
|
|
|
def cask!(cask: nil, download_path: nil, action: true)
|
|
|
|
return if cask.nil? || download_path.nil?
|
2018-09-07 15:37:31 +00:00
|
|
|
|
2018-09-08 14:00:44 +00:00
|
|
|
return if detect(download_path)
|
2018-09-07 15:37:31 +00:00
|
|
|
|
2018-09-08 14:00:44 +00:00
|
|
|
odebug "Quarantining #{download_path}"
|
2018-09-07 15:37:31 +00:00
|
|
|
|
2018-09-08 14:00:44 +00:00
|
|
|
quarantiner = system_command(swift,
|
2018-11-02 17:18:07 +00:00
|
|
|
args: [
|
2018-09-14 15:48:16 +00:00
|
|
|
QUARANTINE_SCRIPT,
|
|
|
|
download_path,
|
|
|
|
cask.url.to_s,
|
|
|
|
cask.homepage.to_s,
|
|
|
|
],
|
|
|
|
print_stderr: false)
|
2018-09-07 15:37:31 +00:00
|
|
|
|
2018-09-08 14:00:44 +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)
|
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-08 20:20:25 +00:00
|
|
|
quarantine_status = toggle_no_translocation_bit(status(from))
|
2018-09-04 21:11:29 +00:00
|
|
|
|
2019-10-15 18:32:37 +02:00
|
|
|
resolved_paths = Pathname.glob(to/"**/*", File::FNM_DOTMATCH).reject(&:symlink?)
|
2018-09-04 21:11:29 +00:00
|
|
|
|
2018-10-08 01:39:52 +00:00
|
|
|
system_command!("/usr/bin/xargs",
|
2018-11-02 17:18:07 +00:00
|
|
|
args: [
|
2018-10-08 01:39:52 +00:00
|
|
|
"-0",
|
|
|
|
"--",
|
|
|
|
"/bin/chmod",
|
|
|
|
"-h",
|
|
|
|
"u+w",
|
|
|
|
],
|
2018-10-08 18:23:21 +00:00
|
|
|
input: resolved_paths.join("\0"))
|
2018-10-08 01:39:52 +00:00
|
|
|
|
2018-09-04 21:11:29 +00:00
|
|
|
quarantiner = system_command("/usr/bin/xargs",
|
2018-11-02 17:18:07 +00:00
|
|
|
args: [
|
2018-09-04 21:11:29 +00:00
|
|
|
"-0",
|
|
|
|
"--",
|
2018-09-26 20:55:54 +00:00
|
|
|
xattr,
|
2018-09-04 21:11:29 +00:00
|
|
|
"-w",
|
|
|
|
QUARANTINE_ATTRIBUTE,
|
|
|
|
quarantine_status,
|
|
|
|
],
|
2018-11-02 17:18:07 +00:00
|
|
|
input: resolved_paths.join("\0"),
|
2018-09-04 21:11:29 +00:00
|
|
|
print_stderr: false)
|
2018-08-31 13:16:11 +00:00
|
|
|
|
|
|
|
return if quarantiner.success?
|
|
|
|
|
|
|
|
raise CaskQuarantinePropagationError.new(to, quarantiner.stderr)
|
|
|
|
end
|
|
|
|
end
|
|
|
|
end
|