vagrant-box-s3 0.1.3 → 0.1.4

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 857a4297cb7c77e6fc882a495a81de46e19ec48481e69394450349f4d2ab1462
4
- data.tar.gz: 54fbc90963cefabf0318fadf73ef4e2370c4438862c75a00041fa727fd4f0780
3
+ metadata.gz: 633fa8c2b30bc3482894cf4f2beb0a1b7d39a8b1cf74ec93d45fb24e93de8a13
4
+ data.tar.gz: 0aed7b6dc1a38fcf0d4542ef8e38fe42c797b688071340f9e898f59267c5450b
5
5
  SHA512:
6
- metadata.gz: 15d7d800c9636bdcc0fbcab656b46d041f57ee018ac20220689135952289603d9dece21ef7b5c7b8700ca9672ba4e7c4231e09d25b1eade790cc7fdd05e7b39b
7
- data.tar.gz: 141d2ca407dfda8c5fa8516732dbbafea8c19a15d9c451645a817b14f177a68362797fb22b57726472acbf9a352758440fc376e2f82b08c97031d6e9be8b6296
6
+ metadata.gz: 2e064c15560beb870b711bb46dce0b5af18c7c2922cf445ea5e78441e77b15befc20168e7330749f2caf5db32b2ccb527bc26446780ff8a07b3df2c5545208a5
7
+ data.tar.gz: cafd52ddd7b9b82fd0393acebaacb94d19c42cadf9fbcf8fec8e7f57c8510ac2a133e8fe775d7255d792818c78200aa869535cafac0abf96ac68912f96606849
data/README.md CHANGED
@@ -11,8 +11,9 @@ Use Vagrant boxes stored in Amazon S3 private buckets.
11
11
 
12
12
  ## Features
13
13
 
14
- This plugin works by monkey patching `Vagrant::Util::Downloader`, extending the core Downloader class in Vagrant to
15
- override the `execute_curl` method to replace S3 box URLs with pre-signed S3 URLs.
14
+ This plugin works using the `authenticate_box_url` hook to replace S3 URLs with presigned URLs and monkey
15
+ patching `Vagrant::Util::Downloader`, extending the core Downloader class in Vagrant to override the `head` method
16
+ used when fetching box metadata URLs from S3.
16
17
 
17
18
  ## Installation
18
19
 
@@ -123,15 +124,15 @@ Update the current version in `lib/vagrant-box-s3/version.rb`.
123
124
 
124
125
  ### Dev build and test
125
126
 
126
- To build the plugin, use `rake build`, this will create a file with the current version number, e.g. `pkg/vagrant-box-s3-0.1.2.gem`.
127
+ To build the plugin, use `rake build`, this will create a file with the current version number, e.g. `pkg/vagrant-box-s3-{VERSION}.gem`.
127
128
 
128
129
  Remove the old version:
129
130
 
130
- vagrant plugin uninstall vagrant-box-s3
131
+ vagrant plugin uninstall vagrant-box-s3 --local
131
132
 
132
133
  Testing the plugin requires installing into vagrant from the build:
133
134
 
134
- vagrant plugin install ../vagrant-box-s3/pkg/vagrant-box-s3-0.1.2.gem
135
+ vagrant plugin install ../vagrant-box-s3/pkg/vagrant-box-s3-{VERSION}.gem
135
136
 
136
137
  Then running a command that will trigger box URL related actions, such as `vagrant up`, `vagrant box update` etc. with the `--debug` flag.
137
138
 
@@ -4,47 +4,24 @@ module Vagrant
4
4
  module Util
5
5
  class Downloader
6
6
 
7
- def aws_auth_download(options, subprocess_options, &data_proc)
8
- # Get URL from options, which is the last option in the list.
9
- url = options.last
7
+ alias_method :original_head, :head
10
8
 
11
- # Determine method from curl command -I flag existence.
12
- method = options.any? { |o| o == '-I' } ? :head_object : :get_object
9
+ def head
10
+ if VagrantPlugins::BoxS3::Utils.is_s3_manifest(@source)
11
+ options, subprocess_options = self.options
12
+ options.unshift("-i")
13
+ options << @source
13
14
 
14
- # Generate pre-signed URL from S3 URL.
15
- presigned_url = VagrantPlugins::BoxS3::Utils.presign_url(method, url, @logger)
15
+ @logger.info("HEAD (Override): #{@source}")
16
+ result = execute_curl(options, subprocess_options)
16
17
 
17
- # Update URL in options.
18
- url.replace(presigned_url.to_s)
19
-
20
- # Call original execute_curl (aliased).
21
- execute_curl_without_aws_auth(options, subprocess_options, &data_proc)
22
-
23
- rescue Aws::Errors::MissingCredentialsError, Aws::Sigv4::Errors::MissingCredentialsError => e
24
- message = "Missing AWS credentials: #{e.message}"
25
- @logger.error(message) if defined?(@logger)
26
- raise Errors::DownloaderError, message: message
27
- rescue Aws::S3::Errors::Forbidden => e
28
- message = "403 Forbidden: #{e.message}"
29
- raise Errors::DownloaderError, message: message
30
- rescue => e
31
- raise Errors::DownloaderError, message: e
32
- end
33
-
34
- def execute_curl_with_aws_auth(options, subprocess_options, &data_proc)
35
- options = options.dup
36
- url = options.find { |o| o =~ /^http/ }
37
-
38
- if url && url.include?('amazonaws.com')
39
- aws_auth_download(options, subprocess_options, &data_proc)
18
+ headers, _body = result.stdout.split("\r\n\r\n", 2)
19
+ headers
40
20
  else
41
- execute_curl_without_aws_auth(options, subprocess_options, &data_proc)
21
+ original_head
42
22
  end
43
23
  end
44
24
 
45
- alias execute_curl_without_aws_auth execute_curl
46
- alias execute_curl execute_curl_with_aws_auth
47
-
48
25
  end
49
26
  end
50
27
  end
@@ -0,0 +1,70 @@
1
+ require 'log4r'
2
+ require 'vagrant-box-s3/utils'
3
+
4
+ module VagrantPlugins
5
+ module BoxS3
6
+ class Urls
7
+ def initialize(app, env)
8
+ @app = app
9
+ @logger = Log4r::Logger.new('vagrant::plugins::box_s3')
10
+ end
11
+
12
+ def call(env)
13
+ # Assume 'env[:box_urls]' contains the original URLs that need authentication
14
+ original_urls = env[:box_urls]
15
+
16
+ # Your logic to authenticate the URLs goes here
17
+ # This is just an example, replace it with your actual authentication mechanism
18
+ authenticated_urls = original_urls.map do |url|
19
+ presign_url(url)
20
+ end
21
+
22
+ # Ensure the authenticated URLs are set back in the environment
23
+ env[:box_urls] = authenticated_urls
24
+
25
+ # Continue the middleware chain
26
+ @app.call(env)
27
+ end
28
+
29
+ private
30
+
31
+ # Pre-sign an s3 URL, with given method.
32
+ def presign_url(url)
33
+
34
+ # Check if the URL is an S3 URL.
35
+ if !Utils.is_s3_url(url)
36
+ @logger.info("Skipping presigner for #{url}")
37
+ return url
38
+ end
39
+
40
+ @logger.info("Discovered S3 URL: #{url}")
41
+
42
+ region, bucket, key = Utils.parse_s3_url(url)
43
+
44
+ profile = ENV['AWS_PROFILE']
45
+
46
+ @logger.debug("Region: #{region}")
47
+ @logger.debug("Bucket: #{bucket}")
48
+ @logger.debug("Key: #{key}")
49
+ @logger.debug("Profile: #{profile}")
50
+
51
+ client = Aws::S3::Client.new(
52
+ profile: profile,
53
+ region: region
54
+ )
55
+ presigner = Aws::S3::Presigner.new(client: client)
56
+
57
+ presigned_url = presigner.presigned_url(
58
+ :get_object,
59
+ bucket: bucket,
60
+ key: key,
61
+ expires_in: 3600
62
+ ).to_s
63
+
64
+ @logger.debug("Pre-signed URL: #{presigned_url}")
65
+
66
+ return presigned_url
67
+ end
68
+ end
69
+ end
70
+ end
@@ -7,13 +7,32 @@ module VagrantPlugins
7
7
 
8
8
  # Match host style URLs, e.g.
9
9
  # https://bucket-name.s3.Region.amazonaws.com/key-name
10
- S3_URL_HOST_REGEX = %r{^https?://([\w\-\.]+)\.s3\.([\w\-]+)\.amazonaws\.com/([^?]+)}
10
+ # https://bucket-name.s3-Region.amazonaws.com/key-name
11
+ S3_URL_HOST_REGEX = %r{^https?://([\w\-\.]+)\.s3[-\.]([\w\-]+)\.amazonaws\.com/([^?]+)}
11
12
 
12
13
  # Match path style URLs e.g.
13
14
  # https://s3.Region.amazonaws.com/bucket-name/key-name
14
15
  # https://s3-Region.amazonaws.com/bucket-name/keyname
15
16
  S3_URL_PATH_REGEX = %r{^https?://s3[-\.]([\w\-]+)\.amazonaws\.com/([^/]+)/([^?]+)}
16
17
 
18
+ # Check if URL matches S3 URLs.
19
+ def self.is_s3_url(url)
20
+ # Check if the URL matches either the host style or path style S3 URL
21
+ matches_host_style = !!(url =~ S3_URL_HOST_REGEX)
22
+ matches_path_style = !!(url =~ S3_URL_PATH_REGEX)
23
+
24
+ # Return true if either match is found, false otherwise
25
+ matches_host_style || matches_path_style
26
+ end
27
+
28
+ # Check if the URL is an S3 URL and the filename is 'manifest.json'
29
+ def self.is_s3_manifest(url)
30
+ uri = URI.parse(url)
31
+ filename = File.basename(uri.path)
32
+
33
+ return is_s3_url(url) && filename == 'manifest.json'
34
+ end
35
+
17
36
  # Parse an s3 URL.
18
37
  def self.parse_s3_url(url)
19
38
  region = bucket = key = nil
@@ -32,66 +51,6 @@ module VagrantPlugins
32
51
  return region, bucket, key
33
52
  end
34
53
 
35
- # Remove presigned URL params from box URL.
36
- # We do this as URLs can be cached and do not want to want
37
- # to include previously presigned URL parameters.
38
- def self.remove_presigned_params(url)
39
- # Parse the URL
40
- uri = URI.parse(url)
41
-
42
- # Split the query string into parameters
43
- query_params = URI.decode_www_form(uri.query || '').to_h
44
-
45
- # Remove any parameters that start with 'X-Amz-'
46
- query_params.reject! { |k, _| k.start_with?('X-Amz-') }
47
-
48
- # Check if there are any query parameters left
49
- if query_params.empty?
50
- # If no query parameters left, set uri.query to nil to remove the '?'
51
- uri.query = nil
52
- else
53
- # Reconstruct the query string without AWS presigned parameters
54
- uri.query = URI.encode_www_form(query_params)
55
- end
56
-
57
- return uri.to_s
58
- end
59
-
60
- # Pre-sign an s3 URL, with given method.
61
- def self.presign_url(method, url, logger)
62
-
63
- url = remove_presigned_params(url)
64
-
65
- logger.info("BoxS3: Generating signed URL for #{method.upcase}")
66
- logger.info("BoxS3: Discovered S3 URL: #{url}")
67
-
68
- region, bucket, key = parse_s3_url(url)
69
-
70
- profile = ENV['AWS_PROFILE']
71
-
72
- logger.debug("BoxS3: Region: #{region}")
73
- logger.debug("BoxS3: Bucket: #{bucket}")
74
- logger.debug("BoxS3: Key: #{key}")
75
- logger.debug("BoxS3: Profile: #{profile}")
76
-
77
- client = Aws::S3::Client.new(
78
- profile: profile,
79
- region: region
80
- )
81
- presigner = Aws::S3::Presigner.new(client: client)
82
-
83
- presigned_url = presigner.presigned_url(
84
- method,
85
- bucket: bucket,
86
- key: key,
87
- expires_in: 3600
88
- ).to_s
89
-
90
- logger.debug("BoxS3: Pre-signed URL: #{presigned_url}")
91
-
92
- return presigned_url
93
- end
94
-
95
54
  end
96
55
  end
97
56
  end
@@ -1,5 +1,5 @@
1
1
  module VagrantPlugins
2
2
  module BoxS3
3
- VERSION = '0.1.3'
3
+ VERSION = '0.1.4'
4
4
  end
5
5
  end
@@ -1,4 +1,5 @@
1
1
  require 'vagrant'
2
+ require 'vagrant-box-s3/urls'
2
3
 
3
4
  module VagrantPlugins
4
5
  module BoxS3
@@ -9,6 +10,10 @@ module VagrantPlugins
9
10
  require_relative 'vagrant-box-s3/downloader'
10
11
  end
11
12
 
13
+ action_hook(:vagrant_box_s3_url, :authenticate_box_url) do |hook|
14
+ hook.prepend(Urls)
15
+ end
16
+
12
17
  end
13
18
  end
14
19
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: vagrant-box-s3
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.1.3
4
+ version: 0.1.4
5
5
  platform: ruby
6
6
  authors:
7
7
  - Steve Whiteley
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2024-02-19 00:00:00.000000000 Z
11
+ date: 2024-02-21 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: aws-sdk-s3
@@ -63,6 +63,7 @@ files:
63
63
  - README.md
64
64
  - lib/vagrant-box-s3.rb
65
65
  - lib/vagrant-box-s3/downloader.rb
66
+ - lib/vagrant-box-s3/urls.rb
66
67
  - lib/vagrant-box-s3/utils.rb
67
68
  - lib/vagrant-box-s3/version.rb
68
69
  homepage: https://github.com/memiah/vagrant-box-s3