Merge pull request #5033 from amyspark/gitjiro-improved
Cask: complete Git-Jiro's HTTPS audit check
This commit is contained in:
commit
2562d270b5
@ -1,6 +1,7 @@
|
||||
require "cask/checkable"
|
||||
require "cask/download"
|
||||
require "digest"
|
||||
require "utils/curl"
|
||||
require "utils/git"
|
||||
|
||||
module Cask
|
||||
@ -30,6 +31,7 @@ module Cask
|
||||
check_generic_artifacts
|
||||
check_token_conflicts
|
||||
check_download
|
||||
check_https_availability
|
||||
check_single_pre_postflight
|
||||
check_single_uninstall_zap
|
||||
check_untrusted_pkg
|
||||
@ -317,5 +319,19 @@ module Cask
|
||||
rescue => e
|
||||
add_error "download not possible: #{e.message}"
|
||||
end
|
||||
|
||||
def check_https_availability
|
||||
return unless download
|
||||
if !cask.url.blank? && !cask.url.using
|
||||
check_url_for_https_availability(cask.url, user_agents: [cask.url.user_agent])
|
||||
end
|
||||
check_url_for_https_availability(cask.appcast) unless cask.appcast.blank?
|
||||
check_url_for_https_availability(cask.homepage) unless cask.homepage.blank?
|
||||
end
|
||||
|
||||
def check_url_for_https_availability(url_to_check, user_agents: [:default])
|
||||
problem = curl_check_http_content(url_to_check.to_s, user_agents: user_agents)
|
||||
add_error problem if problem
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
@ -8,13 +8,13 @@ describe Cask::Cmd::Home, :cask do
|
||||
it_behaves_like "a command that handles invalid options"
|
||||
|
||||
it "opens the homepage for the specified Cask" do
|
||||
expect(described_class).to receive(:open_url).with("https://example.com/local-caffeine")
|
||||
expect(described_class).to receive(:open_url).with("https://example.com")
|
||||
described_class.run("local-caffeine")
|
||||
end
|
||||
|
||||
it "works for multiple Casks" do
|
||||
expect(described_class).to receive(:open_url).with("https://example.com/local-caffeine")
|
||||
expect(described_class).to receive(:open_url).with("https://example.com/local-transmission")
|
||||
expect(described_class).to receive(:open_url).with("https://example.com")
|
||||
expect(described_class).to receive(:open_url).with("https://example.com")
|
||||
described_class.run("local-caffeine", "local-transmission")
|
||||
end
|
||||
|
||||
|
||||
@ -10,7 +10,7 @@ describe Cask::Cmd::Info, :cask do
|
||||
described_class.run("local-caffeine")
|
||||
}.to output(<<~EOS).to_stdout
|
||||
local-caffeine: 1.2.3
|
||||
https://example.com/local-caffeine
|
||||
https://example.com
|
||||
Not installed
|
||||
From: https://github.com/Homebrew/homebrew-cask/blob/master/Casks/local-caffeine.rb
|
||||
==> Name
|
||||
@ -39,7 +39,7 @@ describe Cask::Cmd::Info, :cask do
|
||||
let(:expected_output) {
|
||||
<<~EOS
|
||||
local-caffeine: 1.2.3
|
||||
https://example.com/local-caffeine
|
||||
https://example.com
|
||||
Not installed
|
||||
From: https://github.com/Homebrew/homebrew-cask/blob/master/Casks/local-caffeine.rb
|
||||
==> Name
|
||||
@ -47,7 +47,7 @@ describe Cask::Cmd::Info, :cask do
|
||||
==> Artifacts
|
||||
Caffeine.app (App)
|
||||
local-transmission: 2.61
|
||||
https://example.com/local-transmission
|
||||
https://example.com
|
||||
Not installed
|
||||
From: https://github.com/Homebrew/homebrew-cask/blob/master/Casks/local-transmission.rb
|
||||
==> Name
|
||||
@ -69,7 +69,7 @@ describe Cask::Cmd::Info, :cask do
|
||||
described_class.run("with-caveats")
|
||||
}.to output(<<~EOS).to_stdout
|
||||
with-caveats: 1.2.3
|
||||
https://example.com/local-caffeine
|
||||
https://example.com
|
||||
Not installed
|
||||
From: https://github.com/Homebrew/homebrew-cask/blob/master/Casks/with-caveats.rb
|
||||
==> Name
|
||||
@ -95,7 +95,7 @@ describe Cask::Cmd::Info, :cask do
|
||||
described_class.run("with-conditional-caveats")
|
||||
}.to output(<<~EOS).to_stdout
|
||||
with-conditional-caveats: 1.2.3
|
||||
https://example.com/local-caffeine
|
||||
https://example.com
|
||||
Not installed
|
||||
From: https://github.com/Homebrew/homebrew-cask/blob/master/Casks/with-conditional-caveats.rb
|
||||
==> Name
|
||||
@ -110,7 +110,7 @@ describe Cask::Cmd::Info, :cask do
|
||||
described_class.run("with-languages")
|
||||
}.to output(<<~EOS).to_stdout
|
||||
with-languages: 1.2.3
|
||||
https://example.com/local-caffeine
|
||||
https://example.com
|
||||
Not installed
|
||||
From: https://github.com/Homebrew/homebrew-cask/blob/master/Casks/with-languages.rb
|
||||
==> Name
|
||||
@ -127,7 +127,7 @@ describe Cask::Cmd::Info, :cask do
|
||||
described_class.run("without-languages")
|
||||
}.to output(<<~EOS).to_stdout
|
||||
without-languages: 1.2.3
|
||||
https://example.com/local-caffeine
|
||||
https://example.com
|
||||
Not installed
|
||||
From: https://github.com/Homebrew/homebrew-cask/blob/master/Casks/without-languages.rb
|
||||
==> Name
|
||||
|
||||
@ -3,7 +3,7 @@ describe Cask::Cmd::InternalStanza, :cask do
|
||||
command = described_class.new("homepage", "local-caffeine")
|
||||
expect {
|
||||
command.run
|
||||
}.to output("https://example.com/local-caffeine\n").to_stdout
|
||||
}.to output("https://example.com\n").to_stdout
|
||||
end
|
||||
|
||||
it "raises an exception when stanza is unknown/unsupported" do
|
||||
|
||||
@ -3,7 +3,7 @@ cask 'bad-checksum' do
|
||||
sha256 'badbadbadbadbadbadbadbadbadbadbadbadbadbadbadbadbadbadbadbadbadb'
|
||||
|
||||
url "file://#{TEST_FIXTURE_DIR}/cask/caffeine.zip"
|
||||
homepage 'https://example.com/local-caffeine'
|
||||
homepage 'https://example.com'
|
||||
|
||||
app 'Caffeine.app'
|
||||
end
|
||||
|
||||
@ -3,7 +3,7 @@ cask 'installer-with-uninstall' do
|
||||
sha256 '67cdb8a02803ef37fdbf7e0be205863172e41a561ca446cd84f0d7ab35a99d94'
|
||||
|
||||
url "file://#{TEST_FIXTURE_DIR}/cask/caffeine.zip"
|
||||
homepage 'https://example.com/local-caffeine'
|
||||
homepage 'https://example.com'
|
||||
|
||||
installer manual: 'Caffeine.app'
|
||||
|
||||
|
||||
@ -3,7 +3,7 @@ cask => 'invalid-header-format' do
|
||||
sha256 '67cdb8a02803ef37fdbf7e0be205863172e41a561ca446cd84f0d7ab35a99d94'
|
||||
|
||||
url "file://#{TEST_FIXTURE_DIR}/cask/caffeine.zip"
|
||||
homepage 'https://example.com/local-caffeine'
|
||||
homepage 'https://example.com'
|
||||
|
||||
app 'Caffeine.app'
|
||||
end
|
||||
|
||||
@ -3,7 +3,7 @@ cask 'invalid-header-token-mismatch-this-text-does-not-belong' do
|
||||
sha256 '67cdb8a02803ef37fdbf7e0be205863172e41a561ca446cd84f0d7ab35a99d94'
|
||||
|
||||
url "file://#{TEST_FIXTURE_DIR}/cask/caffeine.zip"
|
||||
homepage 'https://example.com/local-caffeine'
|
||||
homepage 'https://example.com'
|
||||
|
||||
app 'Caffeine.app'
|
||||
end
|
||||
|
||||
@ -3,7 +3,7 @@ cask 'invalid-header-version' do
|
||||
sha256 '67cdb8a02803ef37fdbf7e0be205863172e41a561ca446cd84f0d7ab35a99d94'
|
||||
|
||||
url "file://#{TEST_FIXTURE_DIR}/cask/caffeine.zip"
|
||||
homepage 'https://example.com/local-caffeine'
|
||||
homepage 'https://example.com'
|
||||
|
||||
app 'Caffeine.app'
|
||||
end
|
||||
|
||||
@ -3,7 +3,7 @@ cask 'invalid-two-homepage' do
|
||||
sha256 '67cdb8a02803ef37fdbf7e0be205863172e41a561ca446cd84f0d7ab35a99d94'
|
||||
|
||||
url "file://#{TEST_FIXTURE_DIR}/cask/caffeine.zip"
|
||||
homepage 'https://example.com/local-caffeine'
|
||||
homepage 'https://example.com'
|
||||
homepage 'https://www.example.com/local-caffeine'
|
||||
|
||||
app 'Caffeine.app'
|
||||
|
||||
@ -4,7 +4,7 @@ cask 'invalid-two-url' do
|
||||
|
||||
url "file://#{TEST_FIXTURE_DIR}/cask/caffeine.zip"
|
||||
url 'https://example.com/caffeine.zip'
|
||||
homepage 'https://example.com/local-caffeine'
|
||||
homepage 'https://example.com'
|
||||
|
||||
app 'Caffeine.app'
|
||||
end
|
||||
|
||||
@ -4,7 +4,7 @@ cask 'invalid-two-version' do
|
||||
sha256 '67cdb8a02803ef37fdbf7e0be205863172e41a561ca446cd84f0d7ab35a99d94'
|
||||
|
||||
url "file://#{TEST_FIXTURE_DIR}/cask/caffeine.zip"
|
||||
homepage 'https://example.com/local-caffeine'
|
||||
homepage 'https://example.com'
|
||||
|
||||
app 'Caffeine.app'
|
||||
end
|
||||
|
||||
@ -3,7 +3,7 @@ cask 'local-caffeine' do
|
||||
sha256 '67cdb8a02803ef37fdbf7e0be205863172e41a561ca446cd84f0d7ab35a99d94'
|
||||
|
||||
url "file://#{TEST_FIXTURE_DIR}/cask/caffeine.zip"
|
||||
homepage 'https://example.com/local-caffeine'
|
||||
homepage 'https://example.com'
|
||||
|
||||
app 'Caffeine.app'
|
||||
end
|
||||
|
||||
@ -4,7 +4,7 @@ cask 'local-transmission' do
|
||||
sha256 'e44ffa103fbf83f55c8d0b1bea309a43b2880798dae8620b1ee8da5e1095ec68'
|
||||
|
||||
url "file://#{TEST_FIXTURE_DIR}/cask/transmission-2.61.dmg"
|
||||
homepage 'https://example.com/local-transmission'
|
||||
homepage 'https://example.com'
|
||||
|
||||
app 'Transmission.app'
|
||||
end
|
||||
|
||||
@ -2,7 +2,7 @@ cask 'missing-checksum' do
|
||||
version '1.2.3'
|
||||
|
||||
url "file://#{TEST_FIXTURE_DIR}/cask/caffeine.zip"
|
||||
homepage 'https://example.com/local-caffeine'
|
||||
homepage 'https://example.com'
|
||||
|
||||
app 'Caffeine.app'
|
||||
end
|
||||
|
||||
@ -3,7 +3,7 @@ cask 'no-checksum' do
|
||||
sha256 :no_check
|
||||
|
||||
url "file://#{TEST_FIXTURE_DIR}/cask/caffeine.zip"
|
||||
homepage 'https://example.com/local-caffeine'
|
||||
homepage 'https://example.com'
|
||||
|
||||
app 'Caffeine.app'
|
||||
end
|
||||
|
||||
@ -3,7 +3,7 @@ cask 'bad-checksum' do
|
||||
sha256 '67cdb8a02803ef37fdbf7e0be205863172e41a561ca446cd84f0d7ab35a99d94'
|
||||
|
||||
url "file://#{TEST_FIXTURE_DIR}/cask/caffeine.zip"
|
||||
homepage 'https://example.com/local-caffeine'
|
||||
homepage 'https://example.com'
|
||||
|
||||
app 'Caffeine.app'
|
||||
end
|
||||
|
||||
@ -3,7 +3,7 @@ cask 'local-caffeine' do
|
||||
sha256 '67cdb8a02803ef37fdbf7e0be205863172e41a561ca446cd84f0d7ab35a99d94'
|
||||
|
||||
url "file://#{TEST_FIXTURE_DIR}/cask/caffeine.zip"
|
||||
homepage 'https://example.com/local-caffeine'
|
||||
homepage 'https://example.com'
|
||||
|
||||
app 'Caffeine.app'
|
||||
end
|
||||
|
||||
@ -3,7 +3,7 @@ cask 'local-transmission' do
|
||||
sha256 'e44ffa103fbf83f55c8d0b1bea309a43b2880798dae8620b1ee8da5e1095ec68'
|
||||
|
||||
url "file://#{TEST_FIXTURE_DIR}/cask/transmission-2.61.dmg"
|
||||
homepage 'https://example.com/local-transmission'
|
||||
homepage 'https://example.com'
|
||||
|
||||
app 'Transmission.app'
|
||||
end
|
||||
|
||||
@ -3,7 +3,7 @@ cask 'version-latest' do
|
||||
sha256 :no_check
|
||||
|
||||
url "file://#{TEST_FIXTURE_DIR}/cask/caffeines.zip"
|
||||
homepage 'https://example.com/local-caffeine'
|
||||
homepage 'https://example.com'
|
||||
|
||||
app 'Caffeine Mini.app'
|
||||
app 'Caffeine Pro.app'
|
||||
|
||||
@ -3,7 +3,7 @@ cask 'version-latest' do
|
||||
sha256 :no_check
|
||||
|
||||
url "file://#{TEST_FIXTURE_DIR}/cask/caffeines.zip"
|
||||
homepage 'https://example.com/local-caffeine'
|
||||
homepage 'https://example.com'
|
||||
|
||||
app 'Caffeine Mini.app'
|
||||
app 'Caffeine Pro.app'
|
||||
|
||||
@ -3,7 +3,7 @@ cask 'will-fail-if-upgraded' do
|
||||
sha256 'e44ffa103fbf83f55c8d0b1bea309a43b2880798dae8620b1ee8da5e1095ec68'
|
||||
|
||||
url "file://#{TEST_FIXTURE_DIR}/cask/transmission-2.61.dmg"
|
||||
homepage 'https://example.com/local-transmission'
|
||||
homepage 'https://example.com'
|
||||
|
||||
app 'container'
|
||||
end
|
||||
|
||||
@ -3,7 +3,7 @@ cask 'with-alt-target' do
|
||||
sha256 '67cdb8a02803ef37fdbf7e0be205863172e41a561ca446cd84f0d7ab35a99d94'
|
||||
|
||||
url "file://#{TEST_FIXTURE_DIR}/cask/caffeine.zip"
|
||||
homepage 'https://example.com/local-caffeine'
|
||||
homepage 'https://example.com'
|
||||
|
||||
app 'Caffeine.app', target: 'AnotherName.app'
|
||||
end
|
||||
|
||||
@ -3,7 +3,7 @@ cask 'with-caveats' do
|
||||
sha256 '67cdb8a02803ef37fdbf7e0be205863172e41a561ca446cd84f0d7ab35a99d94'
|
||||
|
||||
url "file://#{TEST_FIXTURE_DIR}/cask/caffeine.zip"
|
||||
homepage 'https://example.com/local-caffeine'
|
||||
homepage 'https://example.com'
|
||||
|
||||
app 'Caffeine.app'
|
||||
|
||||
|
||||
@ -3,7 +3,7 @@ cask 'with-conditional-caveats' do
|
||||
sha256 '67cdb8a02803ef37fdbf7e0be205863172e41a561ca446cd84f0d7ab35a99d94'
|
||||
|
||||
url "file://#{TEST_FIXTURE_DIR}/cask/caffeine.zip"
|
||||
homepage 'https://example.com/local-caffeine'
|
||||
homepage 'https://example.com'
|
||||
|
||||
app 'Caffeine.app'
|
||||
|
||||
|
||||
@ -3,7 +3,7 @@ cask 'with-installer-manual' do
|
||||
sha256 '67cdb8a02803ef37fdbf7e0be205863172e41a561ca446cd84f0d7ab35a99d94'
|
||||
|
||||
url "file://#{TEST_FIXTURE_DIR}/cask/caffeine.zip"
|
||||
homepage 'https://example.com/local-caffeine'
|
||||
homepage 'https://example.com'
|
||||
|
||||
installer manual: 'Caffeine.app'
|
||||
end
|
||||
|
||||
@ -12,7 +12,7 @@ cask 'with-languages' do
|
||||
end
|
||||
|
||||
url "file://#{TEST_FIXTURE_DIR}/cask/caffeine.zip"
|
||||
homepage 'https://example.com/local-caffeine'
|
||||
homepage 'https://example.com'
|
||||
|
||||
app 'Caffeine.app'
|
||||
end
|
||||
|
||||
@ -3,7 +3,7 @@ cask 'with-two-apps-correct' do
|
||||
sha256 '3178fbfd1ea5d87a2a0662a4eb599ebc9a03888e73f37538d9f3f6ee69d2368e'
|
||||
|
||||
url "file://#{TEST_FIXTURE_DIR}/cask/caffeines.zip"
|
||||
homepage 'https://example.com/local-caffeine'
|
||||
homepage 'https://example.com'
|
||||
|
||||
app 'Caffeine Mini.app'
|
||||
app 'Caffeine Pro.app'
|
||||
|
||||
@ -3,7 +3,7 @@ cask 'with-two-apps-subdir' do
|
||||
sha256 'd687c22a21c02bd8f07da9302c8292b93a04df9a929e3f04d09aea6c76f75c65'
|
||||
|
||||
url "file://#{TEST_FIXTURE_DIR}/cask/caffeines-subdir.zip"
|
||||
homepage 'https://example.com/local-caffeine'
|
||||
homepage 'https://example.com'
|
||||
|
||||
app 'Caffeines/Caffeine Mini.app'
|
||||
app 'Caffeines/Caffeine Pro.app'
|
||||
|
||||
@ -3,7 +3,7 @@ cask 'without-languages' do
|
||||
sha256 '67cdb8a02803ef37fdbf7e0be205863172e41a561ca446cd84f0d7ab35a99d94'
|
||||
|
||||
url "file://#{TEST_FIXTURE_DIR}/cask/caffeine.zip"
|
||||
homepage 'https://example.com/local-caffeine'
|
||||
homepage 'https://example.com'
|
||||
|
||||
app 'Caffeine.app'
|
||||
end
|
||||
|
||||
@ -92,6 +92,11 @@ def curl_check_http_content(url, user_agents: [:default], check_content: false,
|
||||
return "The URL #{url} is not reachable (HTTP status code #{details[:status]})"
|
||||
end
|
||||
|
||||
if url.start_with?("https://") && ENV["HOMEBREW_NO_INSECURE_REDIRECT"] &&
|
||||
!details[:final_url].start_with?("https://")
|
||||
return "The URL #{url} redirects back to HTTP"
|
||||
end
|
||||
|
||||
return unless hash_needed
|
||||
|
||||
secure_url = url.sub "http", "https"
|
||||
@ -110,7 +115,9 @@ def curl_check_http_content(url, user_agents: [:default], check_content: false,
|
||||
details[:content_length] == secure_details[:content_length]
|
||||
file_match = details[:file_hash] == secure_details[:file_hash]
|
||||
|
||||
if etag_match || content_length_match || file_match
|
||||
if (etag_match || content_length_match || file_match) &&
|
||||
secure_details[:final_url].start_with?("https://") &&
|
||||
url.start_with?("http://")
|
||||
return "The URL #{url} should use HTTPS rather than HTTP"
|
||||
end
|
||||
|
||||
@ -121,7 +128,9 @@ def curl_check_http_content(url, user_agents: [:default], check_content: false,
|
||||
secure_details[:file] = secure_details[:file].gsub(no_protocol_file_contents, "/")
|
||||
|
||||
# Check for the same content after removing all protocols
|
||||
if details[:file] == secure_details[:file]
|
||||
if (details[:file] == secure_details[:file]) &&
|
||||
secure_details[:final_url].start_with?("https://") &&
|
||||
url.start_with?("http://")
|
||||
return "The URL #{url} should use HTTPS rather than HTTP"
|
||||
end
|
||||
|
||||
@ -150,11 +159,16 @@ def curl_http_content_headers_and_checksum(url, hash_needed: false, user_agent:
|
||||
while status_code == :unknown || status_code.to_s.start_with?("3")
|
||||
headers, _, output = output.partition("\r\n\r\n")
|
||||
status_code = headers[%r{HTTP\/.* (\d+)}, 1]
|
||||
final_url = headers[/^Location:\s*(.*)$/i, 1]&.chomp
|
||||
end
|
||||
|
||||
output_hash = Digest::SHA256.digest(output) if hash_needed
|
||||
|
||||
final_url ||= url
|
||||
|
||||
{
|
||||
url: url,
|
||||
final_url: final_url,
|
||||
status: status_code,
|
||||
etag: headers[%r{ETag: ([wW]\/)?"(([^"]|\\")*)"}, 2],
|
||||
content_length: headers[/Content-Length: (\d+)/, 1],
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user