From 9be6b4f0d3fb12ba4d85b54b5afc19f9d7a4c772 Mon Sep 17 00:00:00 2001 From: Mitchell Hashimoto Date: Sun, 1 Dec 2013 22:18:27 -0800 Subject: [PATCH 01/11] core: check for Ruby 2.0 --- lib/vagrant.rb | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/lib/vagrant.rb b/lib/vagrant.rb index 56c9b9fae..5c4ba81cf 100644 --- a/lib/vagrant.rb +++ b/lib/vagrant.rb @@ -1,3 +1,9 @@ +# Do a Ruby version check early so we can fail fast before any additional +# files are loaded. +if RUBY_VERSION < "2.0.0" + abort "Vagrant requires Ruby 2.0+" +end + require 'log4r' require 'rubygems' From 4281af338f7d2d1a75c102233fab0e699eaab3a2 Mon Sep 17 00:00:00 2001 From: Mitchell Hashimoto Date: Sun, 1 Dec 2013 22:20:51 -0800 Subject: [PATCH 02/11] core: use keyword args to simplify BoxCollection#add --- lib/vagrant/box_collection.rb | 2 +- test/unit/vagrant/box_collection_test.rb | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/lib/vagrant/box_collection.rb b/lib/vagrant/box_collection.rb index cc2ce0d72..b03b6065b 100644 --- a/lib/vagrant/box_collection.rb +++ b/lib/vagrant/box_collection.rb @@ -70,7 +70,7 @@ module Vagrant # the box represents will be added. # @param [Boolean] force If true, any existing box with the same name # and provider will be replaced. - def add(path, name, formats=nil, force=false) + def add(path, name, formats=nil, force: false) formats = [formats] if formats && !formats.is_a?(Array) provider = nil diff --git a/test/unit/vagrant/box_collection_test.rb b/test/unit/vagrant/box_collection_test.rb index 9b098f39e..2bd621b7f 100644 --- a/test/unit/vagrant/box_collection_test.rb +++ b/test/unit/vagrant/box_collection_test.rb @@ -72,7 +72,7 @@ describe Vagrant::BoxCollection do # Attempt to add the box with the same name box_path = environment.box2_file(prev_box_provider, metadata: { "replaced" => "yes" }) - box = instance.add(box_path, prev_box_name, nil, true) + box = instance.add(box_path, prev_box_name, nil, force: true) box.metadata["replaced"].should == "yes" end From 1094ac976e1461b26c2113d493855ea1c5befe6a Mon Sep 17 00:00:00 2001 From: Mitchell Hashimoto Date: Sun, 1 Dec 2013 22:36:41 -0800 Subject: [PATCH 03/11] core: support checksum on box add --- lib/vagrant/action/builtin/box_add.rb | 28 +++++++++++++++++++++++++++ lib/vagrant/errors.rb | 8 ++++++++ lib/vagrant/util/file_checksum.rb | 6 +++--- plugins/commands/box/command/add.rb | 10 ++++++++++ templates/locales/en.yml | 12 ++++++++++++ 5 files changed, 61 insertions(+), 3 deletions(-) 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 From 84ea952df3571d1356a9a328b07e92a90b44fef5 Mon Sep 17 00:00:00 2001 From: Mitchell Hashimoto Date: Sun, 1 Dec 2013 22:39:34 -0800 Subject: [PATCH 04/11] core: output UI when checksumming --- lib/vagrant/action/builtin/box_add.rb | 4 +++- templates/locales/en.yml | 2 ++ 2 files changed, 5 insertions(+), 1 deletion(-) diff --git a/lib/vagrant/action/builtin/box_add.rb b/lib/vagrant/action/builtin/box_add.rb index faf97905b..b362a1c6e 100644 --- a/lib/vagrant/action/builtin/box_add.rb +++ b/lib/vagrant/action/builtin/box_add.rb @@ -19,7 +19,7 @@ module Vagrant @download_interrupted = false # Determine the checksum type to use - checksum = env[:box_checksum] + checksum = env[:box_checksum] || "" checksum_klass = case env[:box_checksum_type] when nil nil @@ -65,6 +65,8 @@ module Vagrant @logger.info("Validating checksum with #{checksum_klass}") @logger.info("Expected checksum: #{checksum}") + env[:ui].info(I18n.t("vagrant.actions.box.add.checksumming", + name: env[:box_name])) actual = FileChecksum.new(@temp_path, checksum_klass).checksum if actual != checksum raise Errors::BoxChecksumMismatch, diff --git a/templates/locales/en.yml b/templates/locales/en.yml index ea1dd51f2..582cd91a4 100644 --- a/templates/locales/en.yml +++ b/templates/locales/en.yml @@ -1133,6 +1133,8 @@ en: Extracting box... added: |- Successfully added box '%{name}' with provider '%{provider}'! + checksumming: |- + Calculating and comparing box checksum... destroy: destroying: "Deleting box '%{name}'..." download: From 555f4c7dcf943b13a6dde7fb2f867d009709d963 Mon Sep 17 00:00:00 2001 From: Mitchell Hashimoto Date: Sun, 1 Dec 2013 22:45:08 -0800 Subject: [PATCH 05/11] kernel/v2: support checksum on box config --- lib/vagrant/action/builtin/handle_box_url.rb | 6 +++++- plugins/kernel_v2/config/vm.rb | 16 ++++++++++++++++ templates/locales/en.yml | 4 ++++ 3 files changed, 25 insertions(+), 1 deletion(-) diff --git a/lib/vagrant/action/builtin/handle_box_url.rb b/lib/vagrant/action/builtin/handle_box_url.rb index eed8f307d..6a71be6a5 100644 --- a/lib/vagrant/action/builtin/handle_box_url.rb +++ b/lib/vagrant/action/builtin/handle_box_url.rb @@ -41,6 +41,8 @@ module Vagrant box_name = env[:machine].config.vm.box box_url = env[:machine].config.vm.box_url box_download_ca_cert = env[:machine].config.vm.box_download_ca_cert + box_download_checksum = env[:machine].config.vm.box_download_checksum + box_download_checksum_type = env[:machine].config.vm.box_download_checksum_type box_download_client_cert = env[:machine].config.vm.box_download_client_cert box_download_insecure = env[:machine].config.vm.box_download_insecure @@ -69,8 +71,10 @@ module Vagrant begin env[:action_runner].run(Vagrant::Action.action_box_add, { - :box_download_ca_cert => box_download_ca_cert, + :box_checksum => box_download_checksum, + :box_checksum_type => box_download_checksum_type, :box_client_cert => box_download_client_cert, + :box_download_ca_cert => box_download_ca_cert, :box_download_insecure => box_download_insecure, :box_name => box_name, :box_provider => box_formats, diff --git a/plugins/kernel_v2/config/vm.rb b/plugins/kernel_v2/config/vm.rb index 191e7a3d1..3de26a12b 100644 --- a/plugins/kernel_v2/config/vm.rb +++ b/plugins/kernel_v2/config/vm.rb @@ -19,6 +19,8 @@ module VagrantPlugins attr_accessor :box attr_accessor :box_url attr_accessor :box_download_ca_cert + attr_accessor :box_download_checksum + attr_accessor :box_download_checksum_type attr_accessor :box_download_client_cert attr_accessor :box_download_insecure attr_accessor :graceful_halt_timeout @@ -30,6 +32,8 @@ module VagrantPlugins def initialize @boot_timeout = UNSET_VALUE @box_download_ca_cert = UNSET_VALUE + @box_download_checksum = UNSET_VALUE + @box_download_checksum_type = UNSET_VALUE @box_download_client_cert = UNSET_VALUE @box_download_insecure = UNSET_VALUE @box_url = UNSET_VALUE @@ -256,6 +260,8 @@ module VagrantPlugins # Defaults @boot_timeout = 300 if @boot_timeout == UNSET_VALUE @box_download_ca_cert = nil if @box_download_ca_cert == UNSET_VALUE + @box_download_checksum = nil if @box_download_checksum == UNSET_VALUE + @box_download_checksum_type = nil if @box_download_checksum_type == UNSET_VALUE @box_download_client_cert = nil if @box_download_client_cert == UNSET_VALUE @box_download_insecure = false if @box_download_insecure == UNSET_VALUE @box_url = nil if @box_url == UNSET_VALUE @@ -385,6 +391,16 @@ module VagrantPlugins end end + if box_download_checksum_type + if box_download_checksum == "" + errors << I18n.t("vagrant.config.vm.box_download_checksum_blank") + end + else + if box_download_checksum != "" + errors << I18n.t("vagrant.config.vm.box_download_checksum_notblank") + end + end + has_nfs = false used_guest_paths = Set.new @__synced_folders.each do |id, options| diff --git a/templates/locales/en.yml b/templates/locales/en.yml index 582cd91a4..cfbdffdec 100644 --- a/templates/locales/en.yml +++ b/templates/locales/en.yml @@ -734,6 +734,10 @@ en: base_mac_invalid: "Base MAC address for eth0/NAT must be set. Contact box maintainer for more information." box_download_ca_cert_not_found: |- "box_download_ca_cert" file not found: %{path} + box_download_checksum_blank: |- + Checksum type specified but "box_download_checksum" is blank + box_download_checksum_notblank: |- + Checksum specified but must also specify "box_download_checksum_type" box_missing: "A box must be specified." box_not_found: "The box '%{name}' could not be found." hostname_invalid_characters: |- From 16dc0507bce156c628b718ff0c73e4fdd1a638aa Mon Sep 17 00:00:00 2001 From: Mitchell Hashimoto Date: Sun, 1 Dec 2013 22:49:11 -0800 Subject: [PATCH 06/11] website/docs: document box checksum flags --- website/docs/source/v2/cli/box.html.md | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/website/docs/source/v2/cli/box.html.md b/website/docs/source/v2/cli/box.html.md index 178054136..dddfef532 100644 --- a/website/docs/source/v2/cli/box.html.md +++ b/website/docs/source/v2/cli/box.html.md @@ -44,6 +44,15 @@ after the initial download. * `--cert CERTFILE` - A client certificate to use when downloading the box, if necessary. +* `--checksum VALUE` - A checksum for the box that is downloaded. If specified, + Vagrant will compare this checksum to what is actually downloaded and will + error if the checksums do not match. This is highly recommended since + box files are so large. If this is specified, `--checksum-type` must + also be specified. + +* `--checksum-type TYPE` - The type of checksum that `--checksum` is if it + is specified. Supported values are currently "md5", "sha1", and "sha256". + * `--clean` - If given, Vagrant will remove any old temporary files from prior downloads of the same URL. This is useful if you don't want Vagrant to resume a download from a previous point, perhaps because the contents From f48f2ff072fbd89bddcadfe40beb767343d5d776 Mon Sep 17 00:00:00 2001 From: Mitchell Hashimoto Date: Sun, 1 Dec 2013 22:51:25 -0800 Subject: [PATCH 07/11] website/docs: document checksumming from Vagrantfile --- .../v2/vagrantfile/machine_settings.html.md | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) diff --git a/website/docs/source/v2/vagrantfile/machine_settings.html.md b/website/docs/source/v2/vagrantfile/machine_settings.html.md index 45e253f3c..2f101252c 100644 --- a/website/docs/source/v2/vagrantfile/machine_settings.html.md +++ b/website/docs/source/v2/vagrantfile/machine_settings.html.md @@ -23,6 +23,23 @@ the installed boxes on the system.
+`config.vm.box_download_checksum` - The checksum of the box specified by +`config.vm.box_url`. If not specified, no checksum comparison will be done. +If specified, Vagrant will compare the checksum of the downloaded box to +this value and error if they do not match. Checksum checking is only done +when Vagrant must download the box. + +If this is specified, then `config.vm.box_download_checksum_type` must +also be specified. + +
+ +`config.vm.box_download_checksum_type` - The type of checksum specified +by `config.vm.box_download_checksum` (if any). Supported values are +currently "md5", "sha1", and "sha256". + +
+ `config.vm.box_download_client_cert` - Path to a client certificate to use when downloading the box, if it is necessary. By default, no client certificate is used to download the box. From 72edddbb0957c64140e8d70a0d0058ee4b2109e3 Mon Sep 17 00:00:00 2001 From: Mitchell Hashimoto Date: Sun, 1 Dec 2013 22:58:25 -0800 Subject: [PATCH 08/11] core: do proper type conversions for box checksum types --- lib/vagrant/action/builtin/box_add.rb | 4 ++-- plugins/commands/box/command/add.rb | 2 +- plugins/kernel_v2/config/vm.rb | 4 ++++ 3 files changed, 7 insertions(+), 3 deletions(-) diff --git a/lib/vagrant/action/builtin/box_add.rb b/lib/vagrant/action/builtin/box_add.rb index b362a1c6e..45a9bfc89 100644 --- a/lib/vagrant/action/builtin/box_add.rb +++ b/lib/vagrant/action/builtin/box_add.rb @@ -19,8 +19,8 @@ module Vagrant @download_interrupted = false # Determine the checksum type to use - checksum = env[:box_checksum] || "" - checksum_klass = case env[:box_checksum_type] + checksum = (env[:box_checksum] || "").to_s + checksum_klass = case env[:box_checksum_type].to_sym when nil nil when :md5 diff --git a/plugins/commands/box/command/add.rb b/plugins/commands/box/command/add.rb index 3af9fb82e..f53283704 100644 --- a/plugins/commands/box/command/add.rb +++ b/plugins/commands/box/command/add.rb @@ -16,7 +16,7 @@ module VagrantPlugins end o.on("--checksum-type VALUE", String, "Checksum type") do |c| - options[:checksum_type] = c + options[:checksum_type] = c.to_sym end o.on("-c", "--clean", "Remove old temporary download if it exists.") do |c| diff --git a/plugins/kernel_v2/config/vm.rb b/plugins/kernel_v2/config/vm.rb index 3de26a12b..f1ee63dde 100644 --- a/plugins/kernel_v2/config/vm.rb +++ b/plugins/kernel_v2/config/vm.rb @@ -270,6 +270,10 @@ module VagrantPlugins @hostname = nil if @hostname == UNSET_VALUE @hostname = @hostname.to_s if @hostname + if @box_download_checksum_type + @box_download_checksum_type = @box_download_checksum_type.to_sym + end + # Make sure the box URL is an array if it is set if @box_url && !@box_url.is_a?(Array) @box_url = [@box_url] From 27a35194fa8dd6dafd02541f69fc1f9c89109508 Mon Sep 17 00:00:00 2001 From: Mitchell Hashimoto Date: Sun, 1 Dec 2013 23:03:50 -0800 Subject: [PATCH 09/11] core: require file checksum for box add --- lib/vagrant/action/builtin/box_add.rb | 1 + 1 file changed, 1 insertion(+) diff --git a/lib/vagrant/action/builtin/box_add.rb b/lib/vagrant/action/builtin/box_add.rb index 45a9bfc89..330b8f633 100644 --- a/lib/vagrant/action/builtin/box_add.rb +++ b/lib/vagrant/action/builtin/box_add.rb @@ -2,6 +2,7 @@ require "digest/sha1" require "log4r" require "vagrant/util/downloader" +require "vagrant/util/file_checksum" require "vagrant/util/platform" module Vagrant From 98fa06044cad94c59eaa72ddc027ae2e2997e6ce Mon Sep 17 00:00:00 2001 From: Mitchell Hashimoto Date: Sun, 1 Dec 2013 23:04:11 -0800 Subject: [PATCH 10/11] Revert "core: check for Ruby 2.0" This reverts commit 9be6b4f0d3fb12ba4d85b54b5afc19f9d7a4c772. --- lib/vagrant.rb | 6 ------ 1 file changed, 6 deletions(-) diff --git a/lib/vagrant.rb b/lib/vagrant.rb index 5c4ba81cf..56c9b9fae 100644 --- a/lib/vagrant.rb +++ b/lib/vagrant.rb @@ -1,9 +1,3 @@ -# Do a Ruby version check early so we can fail fast before any additional -# files are loaded. -if RUBY_VERSION < "2.0.0" - abort "Vagrant requires Ruby 2.0+" -end - require 'log4r' require 'rubygems' From ac45e08cd8ce60c8f76cf7970cb469186422e12a Mon Sep 17 00:00:00 2001 From: Mitchell Hashimoto Date: Sun, 1 Dec 2013 23:04:24 -0800 Subject: [PATCH 11/11] Revert "core: use keyword args to simplify BoxCollection#add" This reverts commit 4281af338f7d2d1a75c102233fab0e699eaab3a2. --- lib/vagrant/box_collection.rb | 2 +- test/unit/vagrant/box_collection_test.rb | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/lib/vagrant/box_collection.rb b/lib/vagrant/box_collection.rb index b03b6065b..cc2ce0d72 100644 --- a/lib/vagrant/box_collection.rb +++ b/lib/vagrant/box_collection.rb @@ -70,7 +70,7 @@ module Vagrant # the box represents will be added. # @param [Boolean] force If true, any existing box with the same name # and provider will be replaced. - def add(path, name, formats=nil, force: false) + def add(path, name, formats=nil, force=false) formats = [formats] if formats && !formats.is_a?(Array) provider = nil diff --git a/test/unit/vagrant/box_collection_test.rb b/test/unit/vagrant/box_collection_test.rb index 2bd621b7f..9b098f39e 100644 --- a/test/unit/vagrant/box_collection_test.rb +++ b/test/unit/vagrant/box_collection_test.rb @@ -72,7 +72,7 @@ describe Vagrant::BoxCollection do # Attempt to add the box with the same name box_path = environment.box2_file(prev_box_provider, metadata: { "replaced" => "yes" }) - box = instance.add(box_path, prev_box_name, nil, force: true) + box = instance.add(box_path, prev_box_name, nil, true) box.metadata["replaced"].should == "yes" end