-
Notifications
You must be signed in to change notification settings - Fork 556
/
Copy pathproject.rb
858 lines (837 loc) · 39.7 KB
/
project.rb
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
# Copyright 2014 Google LLC
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# https://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
require "google/cloud/storage/errors"
require "google/cloud/storage/service"
require "google/cloud/storage/convert"
require "google/cloud/storage/credentials"
require "google/cloud/storage/bucket"
require "google/cloud/storage/bucket/cors"
require "google/cloud/storage/bucket/lifecycle"
require "google/cloud/storage/file"
require "google/cloud/storage/hmac_key"
module Google
module Cloud
module Storage
##
# # Project
#
# Represents the project that storage buckets and files belong to.
# All data in Google Cloud Storage belongs inside a project.
# A project consists of a set of users, a set of APIs, billing,
# authentication, and monitoring settings for those APIs.
#
# Google::Cloud::Storage::Project is the main object for interacting with
# Google Storage. {Google::Cloud::Storage::Bucket} objects are created,
# read, updated, and deleted by Google::Cloud::Storage::Project.
#
# See {Google::Cloud#storage}
#
# @example
# require "google/cloud/storage"
#
# storage = Google::Cloud::Storage.new
#
# bucket = storage.bucket "my-bucket"
# file = bucket.file "path/to/my-file.ext"
#
class Project
include Convert
##
# @private The Service object.
attr_accessor :service
##
# @private Creates a new Project instance.
#
# See {Google::Cloud#storage}
def initialize service
@service = service
end
##
# The universe domain the client is connected to
#
# @return [String]
#
def universe_domain
service.universe_domain
end
##
# The Storage project connected to.
#
# @return [String]
#
# @example
# require "google/cloud/storage"
#
# storage = Google::Cloud::Storage.new(
# project_id: "my-project",
# credentials: "/path/to/keyfile.json"
# )
#
# storage.project_id #=> "my-project"
#
def project_id
service.project
end
alias project project_id
##
# The Google Cloud Storage managed service account created for the
# project used to initialize the client library. (See also
# {#project_id}.)
#
# @return [String] The service account email address.
#
def service_account_email
@service_account_email ||= service.project_service_account.email_address
end
##
# Add custom Google extension headers to the requests that use the signed URLs.
#
# @param [Hash] headers Google extension headers (custom HTTP headers that
# begin with `x-goog-`) to be included in requests that use the signed URLs.
# Provide headers as a key/value array, where the key is
# the header name, and the value is an array of header values.
# For headers with multiple values, provide values as a simple
# array, or a comma-separated string. For a reference of allowed
# headers, see [Reference Headers](https://cloud.google.com/storage/docs/xml-api/reference-headers).
#
# @return [Google::Cloud::Storage::Project] Returns the Project for method chaining
#
def add_custom_headers headers
@service.add_custom_headers headers
self
end
##
# Add custom Google extension header to the requests that use the signed URLs.
#
# @param [String] header_name Name of Google extension header (custom HTTP header that
# begin with `x-goog-`) to be included in requests that use the signed URLs.
# For a reference of allowed headers, see
# [Reference Headers](https://cloud.google.com/storage/docs/xml-api/reference-headers).
# @param [Object] header_value Valid value of the Google extension header being added.
# For headers with multiple values, provide values as a simple array, or a comma-separated string.
#
# @return [Google::Cloud::Storage::Project] Returns the Project for method chaining
#
def add_custom_header header_name, header_value
@service.add_custom_header header_name, header_value
self
end
##
# Retrieves a list of buckets for the given project.
#
# @param [String] prefix Filter results to buckets whose names begin
# with this prefix.
# @param [String] token A previously-returned page token representing
# part of the larger set of results to view.
# @param [Integer] max Maximum number of buckets to return.
# @param [Boolean, String] user_project If this parameter is set to
# `true`, transit costs for operations on the enabled buckets or their
# files will be billed to the current project for this client. (See
# {#project} for the ID of the current project.) If this parameter is
# set to a project ID other than the current project, and that project
# is authorized for the currently authenticated service account,
# transit costs will be billed to the given project. This parameter is
# required with requester pays-enabled buckets. The default is `nil`.
#
# The value provided will be applied to all operations on the returned
# bucket instances and their files.
#
# See also {Bucket#requester_pays=} and {Bucket#requester_pays}.
#
# @return [Array<Google::Cloud::Storage::Bucket>] (See
# {Google::Cloud::Storage::Bucket::List})
#
# @example
# require "google/cloud/storage"
#
# storage = Google::Cloud::Storage.new
#
# buckets = storage.buckets
# buckets.each do |bucket|
# puts bucket.name
# end
#
# @example Retrieve buckets with names that begin with a given prefix:
# require "google/cloud/storage"
#
# storage = Google::Cloud::Storage.new
#
# user_buckets = storage.buckets prefix: "user-"
# user_buckets.each do |bucket|
# puts bucket.name
# end
#
# @example Retrieve all buckets: (See {Bucket::List#all})
# require "google/cloud/storage"
#
# storage = Google::Cloud::Storage.new
#
# buckets = storage.buckets
# buckets.all do |bucket|
# puts bucket.name
# end
#
# @example Retrieve soft deleted buckets
# require "google/cloud/storage"
#
# storage = Google::Cloud::Storage.new
#
# soft_deleted_buckets = storage.buckets soft_deleted: true
# soft_deleted_buckets.each do |bucket|
# puts bucket.name
# end
def buckets prefix: nil, token: nil, max: nil, user_project: nil, soft_deleted: nil
gapi = service.list_buckets \
prefix: prefix, token: token, max: max, user_project: user_project, soft_deleted: soft_deleted
Bucket::List.from_gapi \
gapi, service, prefix, max, user_project: user_project, soft_deleted: soft_deleted
end
alias find_buckets buckets
##
# Retrieves bucket by name.
#
# @param [String] bucket_name Name of a bucket.
# @param [Boolean] skip_lookup Optionally create a Bucket object
# without verifying the bucket resource exists on the Storage service.
# Calls made on this object will raise errors if the bucket resource
# does not exist. Default is `false`.
# @param [Integer] if_metageneration_match Makes the operation conditional
# on whether the bucket's current metageneration matches the given value.
# @param [Integer] if_metageneration_not_match Makes the operation
# conditional on whether the bucket's current metageneration does not
# match the given value.
# @param [Boolean, String] user_project If this parameter is set to
# `true`, transit costs for operations on the requested bucket or a
# file it contains will be billed to the current project for this
# client. (See {#project} for the ID of the current project.) If this
# parameter is set to a project ID other than the current project, and
# that project is authorized for the currently authenticated service
# account, transit costs will be billed to the given project. This
# parameter is required with requester pays-enabled buckets. The
# default is `nil`.
# @param [Integer] generation generation no of bucket
# on whether the bucket's current metageneration matches the given value.
# @param [Boolean] soft_deleted If true, returns the soft-deleted bucket.
# This parameter is required if generation is specified.
#
# The value provided will be applied to all operations on the returned
# bucket instance and its files.
#
# See also {Bucket#requester_pays=} and {Bucket#requester_pays}.
#
# @return [Google::Cloud::Storage::Bucket, nil] Returns nil if bucket
# does not exist
#
# @example
# require "google/cloud/storage"
#
# storage = Google::Cloud::Storage.new
#
# bucket = storage.bucket "my-bucket"
# puts bucket.name
#
# @example With `user_project` set to bill costs to the default project:
# require "google/cloud/storage"
#
# storage = Google::Cloud::Storage.new
#
# bucket = storage.bucket "other-project-bucket", user_project: true
# files = bucket.files # Billed to current project
#
# @example With `user_project` set to a project other than the default:
# require "google/cloud/storage"
#
# storage = Google::Cloud::Storage.new
#
# bucket = storage.bucket "other-project-bucket",
# user_project: "my-other-project"
# files = bucket.files # Billed to "my-other-project"
# @example With `soft_deleted` set to true and generation specified:
# require "google/cloud/storage"
#
# storage = Google::Cloud::Storage.new
#
# bucket = storage.bucket "my-bucket",
# soft_deleted: true,
# generation: 1234567889
# puts bucket.name
#
def bucket bucket_name,
skip_lookup: false,
generation: nil,
soft_deleted: nil,
if_metageneration_match: nil,
if_metageneration_not_match: nil,
user_project: nil
if skip_lookup
return Bucket.new_lazy bucket_name, service,
user_project: user_project
end
gapi = service.get_bucket bucket_name,
if_metageneration_match: if_metageneration_match,
if_metageneration_not_match: if_metageneration_not_match,
user_project: user_project,
soft_deleted: soft_deleted,
generation: generation
Bucket.from_gapi gapi, service, user_project: user_project
rescue Google::Cloud::NotFoundError
nil
end
alias find_bucket bucket
##
# Creates a new bucket with optional attributes. Also accepts a block
# for defining the CORS configuration for a static website served from
# the bucket. See {Bucket::Cors} for details.
#
# The API call to create the bucket may be retried under certain
# conditions. See {Google::Cloud#storage} to control this behavior.
#
# You can pass [website
# settings](https://cloud.google.com/storage/docs/website-configuration)
# for the bucket, including a block that defines CORS rule. See
# {Bucket::Cors} for details.
#
# Before enabling uniform bucket-level access (see
# {Bucket#uniform_bucket_level_access=}) please review [uniform bucket-level
# access](https://cloud.google.com/storage/docs/uniform-bucket-level-access).
#
# @see https://cloud.google.com/storage/docs/cross-origin Cross-Origin
# Resource Sharing (CORS)
# @see https://cloud.google.com/storage/docs/website-configuration How
# to Host a Static Website
#
# @param [String] bucket_name Name of a bucket.
# @param [String] acl Apply a predefined set of access controls to this
# bucket.
#
# Acceptable values are:
#
# * `auth`, `auth_read`, `authenticated`, `authenticated_read`,
# `authenticatedRead` - Project team owners get OWNER access, and
# allAuthenticatedUsers get READER access.
# * `private` - Project team owners get OWNER access.
# * `project_private`, `projectPrivate` - Project team members get
# access according to their roles.
# * `public`, `public_read`, `publicRead` - Project team owners get
# OWNER access, and allUsers get READER access.
# * `public_write`, `publicReadWrite` - Project team owners get OWNER
# access, and allUsers get WRITER access.
# @param [String] default_acl Apply a predefined set of default object
# access controls to this bucket.
#
# Acceptable values are:
#
# * `auth`, `auth_read`, `authenticated`, `authenticated_read`,
# `authenticatedRead` - File owner gets OWNER access, and
# allAuthenticatedUsers get READER access.
# * `owner_full`, `bucketOwnerFullControl` - File owner gets OWNER
# access, and project team owners get OWNER access.
# * `owner_read`, `bucketOwnerRead` - File owner gets OWNER access,
# and project team owners get READER access.
# * `private` - File owner gets OWNER access.
# * `project_private`, `projectPrivate` - File owner gets OWNER
# access, and project team members get access according to their
# roles.
# * `public`, `public_read`, `publicRead` - File owner gets OWNER
# access, and allUsers get READER access.
# @param [String] location The location of the bucket. Optional.
# If not passed, the default location, 'US', will be used.
# If specifying a dual-region location, the `customPlacementConfig`
# property should be set in conjunction. See:
# [Storage Locations](https://cloud.google.com/storage/docs/locations).
# @param [String] logging_bucket The destination bucket for the bucket's
# logs. For more information, see [Access
# Logs](https://cloud.google.com/storage/docs/access-logs).
# @param [String] logging_prefix The prefix used to create log object
# names for the bucket. It can be at most 900 characters and must be a
# [valid object
# name](https://cloud.google.com/storage/docs/bucket-naming#objectnames)
# . By default, the object prefix is the name of the bucket for which
# the logs are enabled. For more information, see [Access
# Logs](https://cloud.google.com/storage/docs/access-logs).
# @param [Symbol, String] storage_class Defines how objects in the
# bucket are stored and determines the SLA and the cost of storage.
# Accepted values include `:standard`, `:nearline`, `:coldline`, and
# `:archive`, as well as the equivalent strings returned by
# {Bucket#storage_class}. For more information, see [Storage
# Classes](https://cloud.google.com/storage/docs/storage-classes). The
# default value is the `:standard` storage class.
# @param [Boolean] versioning Whether [Object
# Versioning](https://cloud.google.com/storage/docs/object-versioning)
# is to be enabled for the bucket. The default value is `false`.
# @param [String] website_main The index page returned from a static
# website served from the bucket when a site visitor requests the top
# level directory. For more information, see [How to Host a Static
# Website
# ](https://cloud.google.com/storage/docs/website-configuration#step4).
# @param [String] website_404 The page returned from a static website
# served from the bucket when a site visitor requests a resource that
# does not exist. For more information, see [How to Host a Static
# Website
# ](https://cloud.google.com/storage/docs/website-configuration#step4).
# @param [String] user_project If this parameter is set to a project ID
# other than the current project, and that project is authorized for
# the currently authenticated service account, transit costs will be
# billed to the given project. The default is `nil`.
# @param [Boolean] autoclass_enabled The bucket's autoclass configuration.
# Buckets can have either StorageClass OLM rules or Autoclass, but
# not both. When Autoclass is enabled on a bucket, adding StorageClass
# OLM rules will result in failure. For more information, see
# [Autoclass](https://cloud.google.com/storage/docs/autoclass).
#
# The value provided will be applied to all operations on the returned
# bucket instance and its files.
#
# See also {Bucket#requester_pays=} and {Bucket#requester_pays}.
# @param [Boolean] enable_object_retention
# When set to true, object retention is enabled for this bucket.
#
# @yield [bucket] a block for configuring the bucket before it is
# created
# @yieldparam [Bucket] bucket the bucket object to be configured
#
# @return [Google::Cloud::Storage::Bucket]
#
# @example
# require "google/cloud/storage"
#
# storage = Google::Cloud::Storage.new
#
# bucket = storage.create_bucket "my-bucket"
#
# @example
# require "google/cloud/storage"
#
# storage = Google::Cloud::Storage.new
#
# bucket = storage.create_bucket "my-bucket", enable_object_retention: true
#
# @example Configure the bucket in a block:
# require "google/cloud/storage"
#
# storage = Google::Cloud::Storage.new
#
# bucket = storage.create_bucket "my-bucket" do |b|
# b.website_main = "index.html"
# b.website_404 = "not_found.html"
# b.requester_pays = true
# b.cors.add_rule ["http://example.org", "https://example.org"],
# "*",
# headers: ["X-My-Custom-Header"],
# max_age: 300
#
# b.lifecycle.add_set_storage_class_rule "COLDLINE", age: 10
# end
#
# rubocop:disable Metrics/CyclomaticComplexity, Metrics/PerceivedComplexity
def create_bucket bucket_name,
acl: nil,
default_acl: nil,
location: nil,
custom_placement_config: nil,
storage_class: nil,
logging_bucket: nil,
logging_prefix: nil,
website_main: nil,
website_404: nil,
versioning: nil,
requester_pays: nil,
user_project: nil,
autoclass_enabled: false,
enable_object_retention: nil,
hierarchical_namespace: nil
params = {
name: bucket_name,
location: location,
custom_placement_config: custom_placement_config,
hierarchical_namespace: hierarchical_namespace
}.delete_if { |_, v| v.nil? }
new_bucket = Google::Apis::StorageV1::Bucket.new(**params)
storage_class = storage_class_for storage_class
updater = Bucket::Updater.new(new_bucket).tap do |b|
b.logging_bucket = logging_bucket unless logging_bucket.nil?
b.logging_prefix = logging_prefix unless logging_prefix.nil?
b.autoclass_enabled = autoclass_enabled
b.storage_class = storage_class unless storage_class.nil?
b.website_main = website_main unless website_main.nil?
b.website_404 = website_404 unless website_404.nil?
b.versioning = versioning unless versioning.nil?
b.requester_pays = requester_pays unless requester_pays.nil?
b.hierarchical_namespace = hierarchical_namespace unless hierarchical_namespace.nil?
end
yield updater if block_given?
updater.check_for_changed_labels!
updater.check_for_mutable_cors!
updater.check_for_mutable_lifecycle!
gapi = service.insert_bucket \
new_bucket, acl: acl_rule(acl), default_acl: acl_rule(default_acl),
user_project: user_project,
enable_object_retention: enable_object_retention
Bucket.from_gapi gapi, service, user_project: user_project
end
# rubocop:enable Metrics/CyclomaticComplexity, Metrics/PerceivedComplexity
##
# Creates a new HMAC key.
#
# @param [String] service_account_email The email address of the service
# account. Used to create the HMAC key.
# @param [String] project_id The project ID associated with
# `service_account_email`, if `service_account_email` belongs to a
# project other than the currently authenticated project. Optional. If
# not provided, the project ID for the current project will be used.
# @param [String] user_project If this parameter is set to a project ID
# other than the current project, and that project is authorized for
# the currently authenticated service account, transit costs will be
# billed to the given project. The default is `nil`.
#
# @return [Google::Cloud::Storage::HmacKey]
#
def create_hmac_key service_account_email, project_id: nil,
user_project: nil
gapi = service.create_hmac_key service_account_email,
project_id: project_id,
user_project: user_project
HmacKey.from_gapi gapi, service, user_project: user_project
end
##
# Retrieves an HMAC key's metadata; the key's secret is not included in
# the representation.
#
# @param [String] project_id The project ID associated with the
# `service_account_email` used to create the HMAC key, if the
# service account email belongs to a project other than the
# currently authenticated project. Optional. If not provided, the
# project ID for current project will be used.
# @param [String] user_project If this parameter is set to a project ID
# other than the current project, and that project is authorized for
# the currently authenticated service account, transit costs will be
# billed to the given project. The default is `nil`.
#
# @return [Google::Cloud::Storage::HmacKey]
#
def hmac_key access_id, project_id: nil, user_project: nil
gapi = service.get_hmac_key \
access_id, project_id: project_id, user_project: user_project
HmacKey.from_gapi_metadata gapi, service, user_project: user_project
end
##
# Retrieves a list of HMAC key metadata matching the criteria; the keys'
# secrets are not included.
#
# @param [String] service_account_email
# If present, only keys for the given service account are returned.
# @param [String] project_id The project ID associated with the
# `service_account_email` used to create the HMAC keys, if the
# service account email belongs to a project other than the
# currently authenticated project. Optional. If not provided, the
# project ID for current project will be used.
# @param [Boolean] show_deleted_keys
# Whether to include keys in the `DELETED` state. The default value is
# false.
# @param [String] token A previously-returned page token representing
# part of the larger set of results to view.
# @param [Integer] max Maximum number of keys to return.
# @param [String] user_project If this parameter is set to a project ID
# other than the current project, and that project is authorized for
# the currently authenticated service account, transit costs will be
# billed to the given project. The default is `nil`.
#
# @return [Google::Cloud::Storage::HmacKey]
#
def hmac_keys service_account_email: nil, project_id: nil,
show_deleted_keys: nil, token: nil, max: nil,
user_project: nil
gapi = service.list_hmac_keys \
max: max, token: token,
service_account_email: service_account_email,
project_id: project_id, show_deleted_keys: show_deleted_keys,
user_project: user_project
HmacKey::List.from_gapi \
gapi, service,
service_account_email: nil, show_deleted_keys: nil,
max: max, user_project: user_project
end
##
# Restores a soft deleted bucket with bucket name and generation.
#
# @param [String] bucket_name Name of the bucket.
# @param [Fixnum] generation Generation of the bucket.
#
# @return [Google::Cloud::Storage::Bucket, nil] Returns nil if bucket
# does not exist
#
# @example
# require "google/cloud/storage"
#
# storage = Google::Cloud::Storage.new
# generation= 123
#
# bucket = storage.restore_bucket "my-bucket", generation
# puts bucket.name
#
def restore_bucket bucket_name,
generation,
options: {}
gapi = service.restore_bucket bucket_name, generation,
options: options
Bucket.from_gapi gapi, service
end
##
# Generates a signed URL. See [Signed
# URLs](https://cloud.google.com/storage/docs/access-control/signed-urls)
# for more information.
#
# Generating a URL requires service account credentials, either by
# connecting with a service account when calling
# {Google::Cloud.storage}, or by passing in the service account `issuer`
# and `signing_key` values. Although the private key can be passed as a
# string for convenience, creating and storing an instance of
# `OpenSSL::PKey::RSA` is more efficient when making multiple calls to
# `signed_url`.
#
# A {SignedUrlUnavailable} is raised if the service account credentials
# are missing. Service account credentials are acquired by following the
# steps in [Service Account Authentication](
# https://cloud.google.com/iam/docs/service-accounts).
#
# @see https://cloud.google.com/storage/docs/access-control/signed-urls
# Signed URLs guide
# @see https://cloud.google.com/storage/docs/access-control/signed-urls#signing-resumable
# Using signed URLs with resumable uploads
#
# @param [String, nil] bucket Name of the bucket, or nil if URL for all
# buckets is desired.
# @param [String] path Path to the file in Google Cloud Storage.
# @param [String] method The HTTP verb to be used with the signed URL.
# Signed URLs can be used
# with `GET`, `HEAD`, `PUT`, and `DELETE` requests. Default is `GET`.
# @param [Integer] expires The number of seconds until the URL expires.
# If the `version` is `:v2`, the default is 300 (5 minutes). If the
# `version` is `:v4`, the default is 604800 (7 days).
# @param [String] content_type When provided, the client (browser) must
# send this value in the HTTP header. e.g. `text/plain`. This param is
# not used if the `version` is `:v4`.
# @param [String] content_md5 The MD5 digest value in base64. If you
# provide this in the string, the client (usually a browser) must
# provide this HTTP header with this same value in its request. This
# param is not used if the `version` is `:v4`.
# @param [Hash] headers Google extension headers (custom HTTP headers
# that begin with `x-goog-`) that must be included in requests that
# use the signed URL.
# @param [String] issuer Service Account's Client Email.
# @param [String] client_email Service Account's Client Email.
# @param [OpenSSL::PKey::RSA, String, Proc] signing_key Service Account's
# Private Key or a Proc that accepts a single String parameter and returns a
# RSA SHA256 signature using a valid Google Service Account Private Key.
# @param [OpenSSL::PKey::RSA, String, Proc] private_key Service Account's
# Private Key or a Proc that accepts a single String parameter and returns a
# RSA SHA256 signature using a valid Google Service Account Private Key.
# @param [OpenSSL::PKey::RSA, String, Proc] signer Service Account's
# Private Key or a Proc that accepts a single String parameter and returns a
# RSA SHA256 signature using a valid Google Service Account Private Key.
#
# When using this method in environments such as GAE Flexible Environment,
# GKE, or Cloud Functions where the private key is unavailable, it may be
# necessary to provide a Proc (or lambda) via the signer parameter. This
# Proc should return a signature created using a RPC call to the
# [Service Account Credentials signBlob](https://cloud.google.com/iam/docs/reference/credentials/rest/v1/projects.serviceAccounts/signBlob)
# method as shown in the example below.
# @param [Hash] query Query string parameters to include in the signed
# URL. The given parameters are not verified by the signature.
#
# Parameters such as `response-content-disposition` and
# `response-content-type` can alter the behavior of the response when
# using the URL, but only when the file resource is missing the
# corresponding values. (These values can be permanently set using
# {File#content_disposition=} and {File#content_type=}.)
# @param [String] scheme The URL scheme. The default value is `HTTPS`.
# @param [Boolean] virtual_hosted_style Whether to use a virtual hosted-style
# hostname, which adds the bucket into the host portion of the URI rather
# than the path, e.g. `https://mybucket.storage.googleapis.com/...`.
# For V4 signing, this also sets the `host` header in the canonicalized
# extension headers to the virtual hosted-style host, unless that header is
# supplied via the `headers` param. The default value of `false` uses the
# form of `https://storage.googleapis.com/mybucket`.
# @param [String] bucket_bound_hostname Use a bucket-bound hostname, which
# replaces the `storage.googleapis.com` host with the name of a `CNAME`
# bucket, e.g. a bucket named `gcs-subdomain.my.domain.tld`, or a Google
# Cloud Load Balancer which routes to a bucket you own, e.g.
# `my-load-balancer-domain.tld`.
# @param [Symbol, String] version The version of the signed credential
# to create. Must be one of `:v2` or `:v4`. The default value is
# `:v2`.
#
# @return [String] The signed URL.
#
# @raise [SignedUrlUnavailable] If the service account credentials
# are missing. Service account credentials are acquired by following the
# steps in [Service Account Authentication](
# https://cloud.google.com/iam/docs/service-accounts).
#
# @example
# require "google/cloud/storage"
#
# storage = Google::Cloud::Storage.new
#
# bucket_name = "my-todo-app"
# file_path = "avatars/heidi/400x400.png"
# shared_url = storage.signed_url bucket_name, file_path
#
# @example Using the `expires` and `version` options:
# require "google/cloud/storage"
#
# storage = Google::Cloud::Storage.new
#
# bucket_name = "my-todo-app"
# file_path = "avatars/heidi/400x400.png"
# shared_url = storage.signed_url bucket_name, file_path,
# expires: 300, # 5 minutes from now
# version: :v4
#
# @example Using the `issuer` and `signing_key` options:
# require "google/cloud/storage"
#
# storage = Google::Cloud::Storage.new
#
# bucket_name = "my-todo-app"
# file_path = "avatars/heidi/400x400.png"
# issuer_email = "[email protected]"
# key = OpenSSL::PKey::RSA.new "-----BEGIN PRIVATE KEY-----\n..."
# shared_url = storage.signed_url bucket_name, file_path,
# issuer: issuer_email,
# signing_key: key
#
# @example Using Cloud IAMCredentials signBlob to create the signature:
# require "google/cloud/storage"
# require "google/apis/iamcredentials_v1"
# require "googleauth"
#
# # Issuer is the service account email that the Signed URL will be signed with
# # and any permission granted in the Signed URL must be granted to the
# # Google Service Account.
# issuer = "[email protected]"
#
# # Create a lambda that accepts the string_to_sign
# signer = lambda do |string_to_sign|
# IAMCredentials = Google::Apis::IamcredentialsV1
# iam_client = IAMCredentials::IAMCredentialsService.new
#
# # Get the environment configured authorization
# scopes = ["https://www.googleapis.com/auth/iam"]
# iam_client.authorization = Google::Auth.get_application_default scopes
#
# request = Google::Apis::IamcredentialsV1::SignBlobRequest.new(
# payload: string_to_sign
# )
# resource = "projects/-/serviceAccounts/#{issuer}"
# response = iam_client.sign_service_account_blob resource, request
# response.signed_blob
# end
#
# storage = Google::Cloud::Storage.new
#
# bucket_name = "my-todo-app"
# file_path = "avatars/heidi/400x400.png"
# url = storage.signed_url bucket_name, file_path,
# method: "GET", issuer: issuer,
# signer: signer
#
# @example Using the `headers` option:
# require "google/cloud/storage"
#
# storage = Google::Cloud::Storage.new
#
# bucket_name = "my-todo-app"
# file_path = "avatars/heidi/400x400.png"
# shared_url = storage.signed_url bucket_name, file_path,
# headers: {
# "x-goog-acl" => "private",
# "x-goog-meta-foo" => "bar,baz"
# }
#
# @example Generating a signed URL for resumable upload:
# require "google/cloud/storage"
#
# storage = Google::Cloud::Storage.new
#
# bucket_name = "my-todo-app"
# file_path = "avatars/heidi/400x400.png"
#
# url = storage.signed_url bucket_name, file_path,
# method: "POST",
# content_type: "image/png",
# headers: {
# "x-goog-resumable" => "start"
# }
# # Send the `x-goog-resumable:start` header and the content type
# # with the resumable upload POST request.
#
def signed_url bucket,
path,
method: "GET",
expires: nil,
content_type: nil,
content_md5: nil,
headers: nil,
issuer: nil,
client_email: nil,
signing_key: nil,
private_key: nil,
signer: nil,
query: nil,
scheme: "HTTPS",
virtual_hosted_style: nil,
bucket_bound_hostname: nil,
version: nil
version ||= :v2
case version.to_sym
when :v2
sign = File::SignerV2.new bucket, path, service
sign.signed_url method: method,
expires: expires,
headers: headers,
content_type: content_type,
content_md5: content_md5,
issuer: issuer,
client_email: client_email,
signing_key: signing_key,
private_key: private_key,
signer: signer,
query: query
when :v4
sign = File::SignerV4.new bucket, path, service
sign.signed_url method: method,
expires: expires,
headers: headers,
issuer: issuer,
client_email: client_email,
signing_key: signing_key,
private_key: private_key,
signer: signer,
query: query,
scheme: scheme,
virtual_hosted_style: virtual_hosted_style,
bucket_bound_hostname: bucket_bound_hostname
else
raise ArgumentError, "version '#{version}' not supported"
end
end
protected
def acl_rule option_name
Bucket::Acl.predefined_rule_for option_name
end
end
end
end
end