diff --git a/lib/vagrant/action/builtin/box_add.rb b/lib/vagrant/action/builtin/box_add.rb index 8f3897dfa..faf97905b 100644 --- a/lib/vagrant/action/builtin/box_add.rb +++ b/lib/vagrant/action/builtin/box_add.rb @@ -18,6 +18,22 @@ module Vagrant def call(env) @download_interrupted = false + # Determine the checksum type to use + checksum = env[:box_checksum] + checksum_klass = case env[:box_checksum_type] + when nil + nil + when :md5 + Digest::MD5 + when :sha1 + Digest::SHA1 + when :sha256 + Digest::SHA2 + else + raise Errors::BoxChecksumInvalidType, + type: env[:box_checksum_type].to_s + end + # Go through each URL and attempt to download it download_error = nil download_url = nil @@ -45,6 +61,18 @@ module Vagrant # If all the URLs failed, then raise an exception raise download_error if download_error + if checksum_klass + @logger.info("Validating checksum with #{checksum_klass}") + @logger.info("Expected checksum: #{checksum}") + + actual = FileChecksum.new(@temp_path, checksum_klass).checksum + if actual != checksum + raise Errors::BoxChecksumMismatch, + actual: actual, + expected: checksum + end + end + box_formats = env[:box_provider] if box_formats # Determine the formats a box can support and allow the box to diff --git a/lib/vagrant/errors.rb b/lib/vagrant/errors.rb index ac3ff70f5..66dc3e6a7 100644 --- a/lib/vagrant/errors.rb +++ b/lib/vagrant/errors.rb @@ -120,6 +120,14 @@ module Vagrant error_key(:already_exists, "vagrant.actions.box.unpackage") end + class BoxChecksumInvalidType < VagrantError + error_key(:box_checksum_invalid_type) + end + + class BoxChecksumMismatch < VagrantError + error_key(:box_checksum_mismatch) + end + class BoxConfigChangingBox < VagrantError error_key(:box_config_changing_box) end diff --git a/lib/vagrant/util/file_checksum.rb b/lib/vagrant/util/file_checksum.rb index b1c00e600..28a21ccd0 100644 --- a/lib/vagrant/util/file_checksum.rb +++ b/lib/vagrant/util/file_checksum.rb @@ -8,7 +8,7 @@ class DigestClass end class FileChecksum - BUFFER_SIZE = 1024 + BUFFER_SIZE = 16328 # Initializes an object to calculate the checksum of a file. The given # ``digest_klass`` should implement the ``DigestClass`` interface. Note @@ -16,7 +16,7 @@ class FileChecksum # Digest::MD5, Digest::SHA1, etc. def initialize(path, digest_klass) @digest_klass = digest_klass - @path = path + @path = path end # This calculates the checksum of the file and returns it as a @@ -24,7 +24,7 @@ class FileChecksum # # @return [String] def checksum - digest= @digest_klass.new + digest = @digest_klass.new File.open(@path, "r") do |f| while !f.eof diff --git a/plugins/commands/box/command/add.rb b/plugins/commands/box/command/add.rb index 3099c6c37..3af9fb82e 100644 --- a/plugins/commands/box/command/add.rb +++ b/plugins/commands/box/command/add.rb @@ -11,6 +11,14 @@ module VagrantPlugins o.banner = "Usage: vagrant box add [--provider provider] [-h]" o.separator "" + o.on("--checksum VALUE", String, "Checksum") do |c| + options[:checksum] = c + end + + o.on("--checksum-type VALUE", String, "Checksum type") do |c| + options[:checksum_type] = c + end + o.on("-c", "--clean", "Remove old temporary download if it exists.") do |c| options[:clean] = c end @@ -51,6 +59,8 @@ module VagrantPlugins :box_name => argv[0], :box_provider => provider, :box_url => argv[1], + :box_checksum_type => options[:checksum_type], + :box_checksum => options[:checksum], :box_clean => options[:clean], :box_force => options[:force], :box_download_ca_cert => options[:ca_cert], diff --git a/templates/locales/en.yml b/templates/locales/en.yml index 1c5562094..ea1dd51f2 100644 --- a/templates/locales/en.yml +++ b/templates/locales/en.yml @@ -177,6 +177,18 @@ en: If the box appears to be booting properly, you may want to increase the timeout ("config.vm.boot_timeout") value. + box_checksum_invalid_type: |- + The specified checksum type is not supported by Vagrant: %{type}. + Vagrant supports the following checksum types: + + md5, sha1, sha256 + box_checksum_mismatch: |- + The checksum of the dowloaded box did not match the expected + value. Please verify that you have the proper URL setup and that + you're downloading the proper file. + + Expected: %{expected} + Received: %{actual} box_config_changing_box: |- While loading the Vagrantfile, the provider override specified a new box. This box, in turn, specified a different box. This isn't