Restrict direct url installs to the file:// scheme

This commit is contained in:
Rylan Polster 2024-07-13 12:16:36 -04:00
parent ab7e49c462
commit 8b0a4a98bf
No known key found for this signature in database
GPG Key ID: 46A744940CFF4D64
4 changed files with 80 additions and 11 deletions

View File

@ -12,6 +12,9 @@ module Cask
module CaskLoader
extend Context
ALLOWED_URL_SCHEMES = %w[file].freeze
private_constant :ALLOWED_URL_SCHEMES
module ILoader
extend T::Helpers
interface!
@ -171,17 +174,25 @@ module Cask
new(uri)
end
attr_reader :url
attr_reader :url, :name
sig { params(url: T.any(URI::Generic, String)).void }
def initialize(url)
@url = URI(url)
super Cache.path/File.basename(T.must(@url.path))
@name = File.basename(T.must(@url.path))
super Cache.path/name
end
def load(config:)
path.dirname.mkpath
if ALLOWED_URL_SCHEMES.exclude?(url.scheme)
raise UnsupportedInstallationMethod,
"Non-checksummed download of #{name} formula file from an arbitrary URL is unsupported! " \
"`brew extract` or `brew create` and `brew tap-new` to create a formula file in a tap " \
"on GitHub instead."
end
begin
ohai "Downloading #{url}"
::Utils::Curl.curl_download url, to: path

View File

@ -17,8 +17,8 @@ module Formulary
extend Context
extend Cachable
URL_START_REGEX = %r{(https?|ftp|file)://}
private_constant :URL_START_REGEX
ALLOWED_URL_SCHEMES = %w[file].freeze
private_constant :ALLOWED_URL_SCHEMES
# `:codesign` and custom requirement classes are not supported.
API_SUPPORTED_REQUIREMENTS = [:arch, :linux, :macos, :maximum_macos, :xcode].freeze
@ -696,7 +696,7 @@ module Formulary
def self.try_new(ref, from: T.unsafe(nil), warn: false)
ref = ref.to_s
new(ref, from:) if URL_START_REGEX.match?(ref)
new(ref, from:) if URI(ref).scheme.present?
end
attr_reader :url
@ -713,12 +713,8 @@ module Formulary
end
def load_file(flags:, ignore_errors:)
match = url.match(%r{githubusercontent.com/[\w-]+/[\w-]+/[a-f0-9]{40}(?:/Formula)?/(?<name>[\w+-.@]+).rb})
if match
raise UnsupportedInstallationMethod,
"Installation of #{match[:name]} from a GitHub commit URL is unsupported! " \
"`brew extract #{match[:name]}` to a stable tap on GitHub instead."
elsif url.match?(%r{^(https?|ftp)://})
url_scheme = URI(url).scheme
if ALLOWED_URL_SCHEMES.exclude?(url_scheme)
raise UnsupportedInstallationMethod,
"Non-checksummed download of #{name} formula file from an arbitrary URL is unsupported! " \
"`brew extract` or `brew create` and `brew tap-new` to create a formula file in a tap " \

View File

@ -18,4 +18,34 @@ RSpec.describe Cask::CaskLoader::FromURILoader do
RUBY
end
end
describe "::load" do
it "raises an error when given an https URL" do
loader = described_class.new("https://brew.sh/foo.rb")
expect do
loader.load(config: nil)
end.to raise_error(UnsupportedInstallationMethod)
end
it "raises an error when given an ftp URL" do
loader = described_class.new("ftp://brew.sh/foo.rb")
expect do
loader.load(config: nil)
end.to raise_error(UnsupportedInstallationMethod)
end
it "raises an error when given an sftp URL" do
loader = described_class.new("sftp://brew.sh/foo.rb")
expect do
loader.load(config: nil)
end.to raise_error(UnsupportedInstallationMethod)
end
it "does not raise an error when given a file URL" do
loader = described_class.new("file://#{TEST_FIXTURE_DIR}/cask/Casks/local-caffeine.rb")
expect do
loader.load(config: nil)
end.not_to raise_error(UnsupportedInstallationMethod)
end
end
end

View File

@ -523,6 +523,38 @@ RSpec.describe Formulary do
end
end
end
context "when passed a URL" do
it "raises an error when given an https URL" do
expect do
described_class.factory("https://brew.sh/foo.rb")
end.to raise_error(UnsupportedInstallationMethod)
end
it "raises an error when given a bottle URL" do
expect do
described_class.factory("https://brew.sh/foo-1.0.arm64_catalina.bottle.tar.gz")
end.to raise_error(UnsupportedInstallationMethod)
end
it "raises an error when given an ftp URL" do
expect do
described_class.factory("ftp://brew.sh/foo.rb")
end.to raise_error(UnsupportedInstallationMethod)
end
it "raises an error when given an sftp URL" do
expect do
described_class.factory("sftp://brew.sh/foo.rb")
end.to raise_error(UnsupportedInstallationMethod)
end
it "does not raise an error when given a file URL" do
expect do
described_class.factory("file://#{TEST_FIXTURE_DIR}/testball.rb")
end.not_to raise_error(UnsupportedInstallationMethod)
end
end
end
specify "::from_contents" do