google-cloud-storage 1.26.1 → 1.29.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -77,13 +77,21 @@ module Google
77
77
  end
78
78
 
79
79
  def determine_signing_key options = {}
80
- options[:signing_key] || options[:private_key] ||
81
- @service.credentials.signing_key
80
+ signing_key = options[:signing_key] || options[:private_key] ||
81
+ options[:signer] || @service.credentials.signing_key
82
+ raise SignedUrlUnavailable, error_msg("signing_key (private_key, signer)") unless signing_key
83
+ signing_key
82
84
  end
83
85
 
84
86
  def determine_issuer options = {}
85
- options[:issuer] || options[:client_email] ||
86
- @service.credentials.issuer
87
+ issuer = options[:issuer] || options[:client_email] || @service.credentials.issuer
88
+ raise SignedUrlUnavailable, error_msg("issuer (client_email)") unless issuer
89
+ issuer
90
+ end
91
+
92
+ def error_msg attr_name
93
+ "Service account credentials '#{attr_name}' is missing. To generate service account credentials " \
94
+ "see https://cloud.google.com/iam/docs/service-accounts"
87
95
  end
88
96
 
89
97
  def post_object options
@@ -99,8 +107,6 @@ module Google
99
107
  i = determine_issuer options
100
108
  s = determine_signing_key options
101
109
 
102
- raise SignedUrlUnavailable unless i && s
103
-
104
110
  policy_str = p.to_json
105
111
  policy = Base64.strict_encode64(policy_str).delete "\n"
106
112
 
@@ -119,18 +125,21 @@ module Google
119
125
  i = determine_issuer options
120
126
  s = determine_signing_key options
121
127
 
122
- raise SignedUrlUnavailable unless i && s
123
-
124
128
  sig = generate_signature s, signature_str(options)
125
129
  generate_signed_url i, sig, options[:expires], options[:query]
126
130
  end
127
131
 
128
132
  def generate_signature signing_key, secret
129
- unless signing_key.respond_to? :sign
130
- signing_key = OpenSSL::PKey::RSA.new signing_key
133
+ unencoded_signature = ""
134
+ if signing_key.is_a? Proc
135
+ unencoded_signature = signing_key.call secret
136
+ else
137
+ unless signing_key.respond_to? :sign
138
+ signing_key = OpenSSL::PKey::RSA.new signing_key
139
+ end
140
+ unencoded_signature = signing_key.sign OpenSSL::Digest::SHA256.new, secret
131
141
  end
132
- signature = signing_key.sign OpenSSL::Digest::SHA256.new, secret
133
- Base64.strict_encode64(signature).delete "\n"
142
+ Base64.strict_encode64(unencoded_signature).delete "\n"
134
143
  end
135
144
 
136
145
  def generate_signed_url issuer, signed_string, expires, query
@@ -43,6 +43,7 @@ module Google
43
43
  client_email: nil,
44
44
  signing_key: nil,
45
45
  private_key: nil,
46
+ signer: nil,
46
47
  expires: nil,
47
48
  fields: nil,
48
49
  conditions: nil,
@@ -50,8 +51,7 @@ module Google
50
51
  virtual_hosted_style: nil,
51
52
  bucket_bound_hostname: nil
52
53
  i = determine_issuer issuer, client_email
53
- s = determine_signing_key signing_key, private_key
54
- raise SignedUrlUnavailable unless i && s
54
+ s = determine_signing_key signing_key, private_key, signer
55
55
 
56
56
  now = Time.now.utc
57
57
  base_fields = required_fields i, now
@@ -82,12 +82,13 @@ module Google
82
82
  client_email: nil,
83
83
  signing_key: nil,
84
84
  private_key: nil,
85
+ signer: nil,
85
86
  query: nil,
86
87
  scheme: "https",
87
88
  virtual_hosted_style: nil,
88
89
  bucket_bound_hostname: nil
89
90
  raise ArgumentError, "method is required" unless method
90
- issuer, signer = issuer_and_signer issuer, client_email, signing_key, private_key
91
+ issuer, signer = issuer_and_signer issuer, client_email, signing_key, private_key, signer
91
92
  datetime_now = Time.now.utc
92
93
  goog_date = datetime_now.strftime "%Y%m%dT%H%M%SZ"
93
94
  datestamp = datetime_now.strftime "%Y%m%d"
@@ -192,28 +193,40 @@ module Google
192
193
  def determine_issuer issuer, client_email
193
194
  # Parse the Service Account and get client id and private key
194
195
  issuer = issuer || client_email || @service.credentials.issuer
195
- raise SignedUrlUnavailable, "issuer (client_email) missing" unless issuer
196
+ raise SignedUrlUnavailable, error_msg("issuer (client_email)") unless issuer
196
197
  issuer
197
198
  end
198
199
 
199
- def determine_signing_key signing_key, private_key
200
- signing_key = signing_key || private_key || @service.credentials.signing_key
201
- raise SignedUrlUnavailable, "signing_key (private_key) missing" unless signing_key
200
+ def determine_signing_key signing_key, private_key, signer
201
+ signing_key = signing_key || private_key || signer || @service.credentials.signing_key
202
+ raise SignedUrlUnavailable, error_msg("signing_key (private_key, signer)") unless signing_key
202
203
  signing_key
203
204
  end
204
205
 
206
+ def error_msg attr_name
207
+ "Service account credentials '#{attr_name}' is missing. To generate service account credentials " \
208
+ "see https://cloud.google.com/iam/docs/service-accounts"
209
+ end
210
+
205
211
  def service_account_signer signer
206
- signer = OpenSSL::PKey::RSA.new signer unless signer.respond_to? :sign
207
- # Sign string to sign
208
- lambda do |string_to_sign|
209
- sig = signer.sign OpenSSL::Digest::SHA256.new, string_to_sign
210
- sig.unpack("H*").first
212
+ if signer.is_a? Proc
213
+ lambda do |string_to_sign|
214
+ sig = signer.call string_to_sign
215
+ sig.unpack("H*").first
216
+ end
217
+ else
218
+ signer = OpenSSL::PKey::RSA.new signer unless signer.respond_to? :sign
219
+ # Sign string to sign
220
+ lambda do |string_to_sign|
221
+ sig = signer.sign OpenSSL::Digest::SHA256.new, string_to_sign
222
+ sig.unpack("H*").first
223
+ end
211
224
  end
212
225
  end
213
226
 
214
- def issuer_and_signer issuer, client_email, signing_key, private_key
227
+ def issuer_and_signer issuer, client_email, signing_key, private_key, signer
215
228
  issuer = determine_issuer issuer, client_email
216
- signing_key = determine_signing_key signing_key, private_key
229
+ signing_key = determine_signing_key signing_key, private_key, signer
217
230
  signer = service_account_signer signing_key
218
231
  [issuer, signer]
219
232
  end
@@ -260,7 +273,7 @@ module Google
260
273
  # Only the characters in the regex set [A-Za-z0-9.~_-] must be left un-escaped; all others must be
261
274
  # percent-encoded using %XX UTF-8 style.
262
275
  def escape_query_param str
263
- CGI.escape(str.to_s).gsub("%7E", "~")
276
+ CGI.escape(str.to_s).gsub("%7E", "~").gsub "+", "%20"
264
277
  end
265
278
 
266
279
  def host_name virtual_hosted_style, bucket_bound_hostname
@@ -274,7 +287,7 @@ module Google
274
287
  path = []
275
288
  path << "/#{@bucket_name}" if path_style
276
289
  path << "/#{String(@file_name)}" if @file_name && !@file_name.empty?
277
- CGI.escape(path.join).gsub "%2F", "/"
290
+ CGI.escape(path.join).gsub("%2F", "/").gsub "+", "%20"
278
291
  end
279
292
 
280
293
  ##
@@ -337,11 +350,16 @@ module Google
337
350
  end
338
351
 
339
352
  def generate_signature signing_key, data
340
- unless signing_key.respond_to? :sign
341
- signing_key = OpenSSL::PKey::RSA.new signing_key
353
+ packed_signature = nil
354
+ if signing_key.is_a? Proc
355
+ packed_signature = signing_key.call data
356
+ else
357
+ unless signing_key.respond_to? :sign
358
+ signing_key = OpenSSL::PKey::RSA.new signing_key
359
+ end
360
+ packed_signature = signing_key.sign OpenSSL::Digest::SHA256.new, data
342
361
  end
343
- signature = signing_key.sign OpenSSL::Digest::SHA256.new, data
344
- signature.unpack("H*").first.force_encoding "utf-8"
362
+ packed_signature.unpack("H*").first.force_encoding "utf-8"
345
363
  end
346
364
  end
347
365
  end
@@ -483,7 +483,7 @@ module Google
483
483
  # A {SignedUrlUnavailable} is raised if the service account credentials
484
484
  # are missing. Service account credentials are acquired by following the
485
485
  # steps in [Service Account Authentication](
486
- # https://cloud.google.com/storage/docs/authentication#service_accounts).
486
+ # https://cloud.google.com/iam/docs/service-accounts).
487
487
  #
488
488
  # @see https://cloud.google.com/storage/docs/access-control/signed-urls
489
489
  # Signed URLs guide
@@ -511,10 +511,22 @@ module Google
511
511
  # use the signed URL.
512
512
  # @param [String] issuer Service Account's Client Email.
513
513
  # @param [String] client_email Service Account's Client Email.
514
- # @param [OpenSSL::PKey::RSA, String] signing_key Service Account's
515
- # Private Key.
516
- # @param [OpenSSL::PKey::RSA, String] private_key Service Account's
517
- # Private Key.
514
+ # @param [OpenSSL::PKey::RSA, String, Proc] signing_key Service Account's
515
+ # Private Key or a Proc that accepts a single String parameter and returns a
516
+ # RSA SHA256 signature using a valid Google Service Account Private Key.
517
+ # @param [OpenSSL::PKey::RSA, String, Proc] private_key Service Account's
518
+ # Private Key or a Proc that accepts a single String parameter and returns a
519
+ # RSA SHA256 signature using a valid Google Service Account Private Key.
520
+ # @param [OpenSSL::PKey::RSA, String, Proc] signer Service Account's
521
+ # Private Key or a Proc that accepts a single String parameter and returns a
522
+ # RSA SHA256 signature using a valid Google Service Account Private Key.
523
+ #
524
+ # When using this method in environments such as GAE Flexible Environment,
525
+ # GKE, or Cloud Functions where the private key is unavailable, it may be
526
+ # necessary to provide a Proc (or lambda) via the signer parameter. This
527
+ # Proc should return a signature created using a RPC call to the
528
+ # [Service Account Credentials signBlob](https://cloud.google.com/iam/docs/reference/credentials/rest/v1/projects.serviceAccounts/signBlob)
529
+ # method as shown in the example below.
518
530
  # @param [Hash] query Query string parameters to include in the signed
519
531
  # URL. The given parameters are not verified by the signature.
520
532
  #
@@ -540,7 +552,12 @@ module Google
540
552
  # to create. Must be one of `:v2` or `:v4`. The default value is
541
553
  # `:v2`.
542
554
  #
543
- # @return [String]
555
+ # @return [String] The signed URL.
556
+ #
557
+ # @raise [SignedUrlUnavailable] If the service account credentials
558
+ # are missing. Service account credentials are acquired by following the
559
+ # steps in [Service Account Authentication](
560
+ # https://cloud.google.com/iam/docs/service-accounts).
544
561
  #
545
562
  # @example
546
563
  # require "google/cloud/storage"
@@ -575,6 +592,41 @@ module Google
575
592
  # issuer: issuer_email,
576
593
  # signing_key: key
577
594
  #
595
+ # @example Using Cloud IAMCredentials signBlob to create the signature:
596
+ # require "google/cloud/storage"
597
+ # require "google/apis/iamcredentials_v1"
598
+ # require "googleauth"
599
+ #
600
+ # # Issuer is the service account email that the Signed URL will be signed with
601
+ # # and any permission granted in the Signed URL must be granted to the
602
+ # # Google Service Account.
603
+ # issuer = "service-account@project-id.iam.gserviceaccount.com"
604
+ #
605
+ # # Create a lambda that accepts the string_to_sign
606
+ # signer = lambda do |string_to_sign|
607
+ # IAMCredentials = Google::Apis::IamcredentialsV1
608
+ # iam_client = IAMCredentials::IAMCredentialsService.new
609
+ #
610
+ # # Get the environment configured authorization
611
+ # scopes = ["https://www.googleapis.com/auth/iam"]
612
+ # iam_client.authorization = Google::Auth.get_application_default scopes
613
+ #
614
+ # request = {
615
+ # "payload": string_to_sign,
616
+ # }
617
+ # resource = "projects/-/serviceAccounts/#{issuer}"
618
+ # response = iam_client.sign_service_account_blob resource, request, {}
619
+ # response.signed_blob
620
+ # end
621
+ #
622
+ # storage = Google::Cloud::Storage.new
623
+ #
624
+ # bucket_name = "my-todo-app"
625
+ # file_path = "avatars/heidi/400x400.png"
626
+ # url = storage.signed_url bucket_name, file_path,
627
+ # method: "GET", issuer: issuer,
628
+ # signer: signer
629
+ #
578
630
  # @example Using the `headers` option:
579
631
  # require "google/cloud/storage"
580
632
  #
@@ -616,6 +668,7 @@ module Google
616
668
  client_email: nil,
617
669
  signing_key: nil,
618
670
  private_key: nil,
671
+ signer: nil,
619
672
  query: nil,
620
673
  scheme: "HTTPS",
621
674
  virtual_hosted_style: nil,
@@ -624,31 +677,32 @@ module Google
624
677
  version ||= :v2
625
678
  case version.to_sym
626
679
  when :v2
627
- signer = File::SignerV2.new bucket, path, service
628
-
629
- signer.signed_url method: method,
630
- expires: expires,
631
- headers: headers,
632
- content_type: content_type,
633
- content_md5: content_md5,
634
- issuer: issuer,
635
- client_email: client_email,
636
- signing_key: signing_key,
637
- private_key: private_key,
638
- query: query
680
+ sign = File::SignerV2.new bucket, path, service
681
+ sign.signed_url method: method,
682
+ expires: expires,
683
+ headers: headers,
684
+ content_type: content_type,
685
+ content_md5: content_md5,
686
+ issuer: issuer,
687
+ client_email: client_email,
688
+ signing_key: signing_key,
689
+ private_key: private_key,
690
+ signer: signer,
691
+ query: query
639
692
  when :v4
640
- signer = File::SignerV4.new bucket, path, service
641
- signer.signed_url method: method,
642
- expires: expires,
643
- headers: headers,
644
- issuer: issuer,
645
- client_email: client_email,
646
- signing_key: signing_key,
647
- private_key: private_key,
648
- query: query,
649
- scheme: scheme,
650
- virtual_hosted_style: virtual_hosted_style,
651
- bucket_bound_hostname: bucket_bound_hostname
693
+ sign = File::SignerV4.new bucket, path, service
694
+ sign.signed_url method: method,
695
+ expires: expires,
696
+ headers: headers,
697
+ issuer: issuer,
698
+ client_email: client_email,
699
+ signing_key: signing_key,
700
+ private_key: private_key,
701
+ signer: signer,
702
+ query: query,
703
+ scheme: scheme,
704
+ virtual_hosted_style: virtual_hosted_style,
705
+ bucket_bound_hostname: bucket_bound_hostname
652
706
  else
653
707
  raise ArgumentError, "version '#{version}' not supported"
654
708
  end
@@ -39,7 +39,7 @@ module Google
39
39
  ##
40
40
  # Creates a new Service instance.
41
41
  def initialize project, credentials,
42
- retries: nil, timeout: nil, host: nil
42
+ retries: nil, timeout: nil, host: nil, quota_project: nil
43
43
  @project = project
44
44
  @credentials = credentials
45
45
  @service = API::StorageService.new
@@ -55,6 +55,7 @@ module Google
55
55
  @service.request_options.header["x-goog-api-client"] = \
56
56
  "gl-ruby/#{RUBY_VERSION} gccl/#{Google::Cloud::Storage::VERSION}"
57
57
  @service.request_options.header["Accept-Encoding"] = "gzip"
58
+ @service.request_options.quota_project = quota_project if quota_project
58
59
  @service.authorization = @credentials.client if @credentials
59
60
  @service.root_url = host if host
60
61
  end
@@ -292,12 +293,12 @@ module Google
292
293
  def insert_file bucket_name, source, path = nil, acl: nil,
293
294
  cache_control: nil, content_disposition: nil,
294
295
  content_encoding: nil, content_language: nil,
295
- content_type: nil, crc32c: nil, md5: nil, metadata: nil,
296
+ content_type: nil, custom_time: nil, crc32c: nil, md5: nil, metadata: nil,
296
297
  storage_class: nil, key: nil, kms_key: nil,
297
298
  temporary_hold: nil, event_based_hold: nil,
298
299
  user_project: nil
299
300
  params =
300
- { cache_control: cache_control, content_type: content_type,
301
+ { cache_control: cache_control, content_type: content_type, custom_time: custom_time,
301
302
  content_disposition: content_disposition, md5_hash: md5,
302
303
  content_encoding: content_encoding, crc32c: crc32c,
303
304
  content_language: content_language, metadata: metadata,
@@ -16,7 +16,7 @@
16
16
  module Google
17
17
  module Cloud
18
18
  module Storage
19
- VERSION = "1.26.1".freeze
19
+ VERSION = "1.29.1".freeze
20
20
  end
21
21
  end
22
22
  end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: google-cloud-storage
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.26.1
4
+ version: 1.29.1
5
5
  platform: ruby
6
6
  authors:
7
7
  - Mike Moore
@@ -9,7 +9,7 @@ authors:
9
9
  autorequire:
10
10
  bindir: bin
11
11
  cert_chain: []
12
- date: 2020-05-06 00:00:00.000000000 Z
12
+ date: 2020-10-05 00:00:00.000000000 Z
13
13
  dependencies:
14
14
  - !ruby/object:Gem::Dependency
15
15
  name: google-cloud-core
@@ -298,7 +298,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
298
298
  - !ruby/object:Gem::Version
299
299
  version: '0'
300
300
  requirements: []
301
- rubygems_version: 3.0.6
301
+ rubygems_version: 3.1.4
302
302
  signing_key:
303
303
  specification_version: 4
304
304
  summary: API Client library for Google Cloud Storage