google-cloud-storage 1.25.1 → 1.26.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/CHANGELOG.md +17 -0
- data/lib/google/cloud/storage/bucket.rb +175 -41
- data/lib/google/cloud/storage/file.rb +48 -15
- data/lib/google/cloud/storage/file/list.rb +7 -5
- data/lib/google/cloud/storage/file/signer_v4.rb +219 -53
- data/lib/google/cloud/storage/policy/binding.rb +3 -2
- data/lib/google/cloud/storage/post_object.rb +18 -1
- data/lib/google/cloud/storage/project.rb +49 -13
- data/lib/google/cloud/storage/service.rb +10 -13
- data/lib/google/cloud/storage/version.rb +1 -1
- metadata +2 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 6a69b7d03384d604c8b96548b952b6894af09ee7cef01845fe92b998ea77bcc8
|
4
|
+
data.tar.gz: 9fd54043ddab11b2284c73b17e780877b795a59593943deef43b9d14fbb4da1e
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 36d6b3d59ab2655020f97e7d15a33a35b48a541632e03a6a8aa01f20289c821b9582cf21fdea2799cad8111c8208bd866154246a8ec69fb33102fd78853bc49f
|
7
|
+
data.tar.gz: 8d59996b1108a4c44e074e9762e48ad4a1f93c8dfd07efa11b77472a3b2285be52ce1486afa76b5301de683cf918c23d41d1d0dd877cd4bbaf0ab3d1cc91e405
|
data/CHANGELOG.md
CHANGED
@@ -1,5 +1,22 @@
|
|
1
1
|
# Release History
|
2
2
|
|
3
|
+
### 1.26.0 / 2020-04-06
|
4
|
+
|
5
|
+
#### Features
|
6
|
+
|
7
|
+
* Update V4 Signature support in Project#signed_url, Bucket#signed_url and File#signed_url
|
8
|
+
* Add scheme, virtual_hosted_style and bucket_bound_hostname to #signed_url methods
|
9
|
+
* Add support for V4 query param encoding and ordering
|
10
|
+
* Convert tabs in V4 to single whitespace character
|
11
|
+
* Set payload in V4 to X-Goog-Content-SHA256 if present
|
12
|
+
* Fix method param default value GET for #signed_url
|
13
|
+
* Add support for V4 Signature POST Policies
|
14
|
+
* Add Bucket#generate_signed_post_policy_v4
|
15
|
+
|
16
|
+
#### Bug Fixes
|
17
|
+
|
18
|
+
* Address keyword argument warnings in Ruby 2.7 and later
|
19
|
+
|
3
20
|
### 1.25.1 / 2020-01-06
|
4
21
|
|
5
22
|
#### Documentation
|
@@ -1254,22 +1254,27 @@ module Google
|
|
1254
1254
|
storage_class: nil, encryption_key: nil, kms_key: nil,
|
1255
1255
|
temporary_hold: nil, event_based_hold: nil
|
1256
1256
|
ensure_service!
|
1257
|
-
options = { acl: File::Acl.predefined_rule_for(acl), md5: md5,
|
1258
|
-
cache_control: cache_control, content_type: content_type,
|
1259
|
-
content_disposition: content_disposition, crc32c: crc32c,
|
1260
|
-
content_encoding: content_encoding, metadata: metadata,
|
1261
|
-
content_language: content_language, key: encryption_key,
|
1262
|
-
kms_key: kms_key,
|
1263
|
-
storage_class: storage_class_for(storage_class),
|
1264
|
-
temporary_hold: temporary_hold,
|
1265
|
-
event_based_hold: event_based_hold,
|
1266
|
-
user_project: user_project }
|
1267
1257
|
ensure_io_or_file_exists! file
|
1268
1258
|
path ||= file.path if file.respond_to? :path
|
1269
1259
|
path ||= file if file.is_a? String
|
1270
1260
|
raise ArgumentError, "must provide path" if path.nil?
|
1271
1261
|
|
1272
|
-
|
1262
|
+
|
1263
|
+
gapi = service.insert_file name, file, path, acl: File::Acl.predefined_rule_for(acl),
|
1264
|
+
md5: md5,
|
1265
|
+
cache_control: cache_control,
|
1266
|
+
content_type: content_type,
|
1267
|
+
content_disposition: content_disposition,
|
1268
|
+
crc32c: crc32c,
|
1269
|
+
content_encoding: content_encoding,
|
1270
|
+
metadata: metadata,
|
1271
|
+
content_language: content_language,
|
1272
|
+
key: encryption_key,
|
1273
|
+
kms_key: kms_key,
|
1274
|
+
storage_class: storage_class_for(storage_class),
|
1275
|
+
temporary_hold: temporary_hold,
|
1276
|
+
event_based_hold: event_based_hold,
|
1277
|
+
user_project: user_project
|
1273
1278
|
File.from_gapi gapi, service, user_project: user_project
|
1274
1279
|
end
|
1275
1280
|
alias upload_file create_file
|
@@ -1368,9 +1373,6 @@ module Google
|
|
1368
1373
|
raise ArgumentError, "must provide at least two source files"
|
1369
1374
|
end
|
1370
1375
|
|
1371
|
-
options = { acl: File::Acl.predefined_rule_for(acl),
|
1372
|
-
key: encryption_key,
|
1373
|
-
user_project: user_project }
|
1374
1376
|
destination_gapi = nil
|
1375
1377
|
if block_given?
|
1376
1378
|
destination_gapi = API::Object.new
|
@@ -1378,8 +1380,11 @@ module Google
|
|
1378
1380
|
yield updater
|
1379
1381
|
updater.check_for_changed_metadata!
|
1380
1382
|
end
|
1381
|
-
|
1382
|
-
|
1383
|
+
|
1384
|
+
acl_rule = File::Acl.predefined_rule_for acl
|
1385
|
+
gapi = service.compose_file name, sources, destination, destination_gapi, acl: acl_rule,
|
1386
|
+
key: encryption_key,
|
1387
|
+
user_project: user_project
|
1383
1388
|
File.from_gapi gapi, service, user_project: user_project
|
1384
1389
|
end
|
1385
1390
|
alias compose_file compose
|
@@ -1440,6 +1445,19 @@ module Google
|
|
1440
1445
|
# using the URL, but only when the file resource is missing the
|
1441
1446
|
# corresponding values. (These values can be permanently set using
|
1442
1447
|
# {File#content_disposition=} and {File#content_type=}.)
|
1448
|
+
# @param [String] scheme The URL scheme. The default value is `HTTPS`.
|
1449
|
+
# @param [Boolean] virtual_hosted_style Whether to use a virtual hosted-style
|
1450
|
+
# hostname, which adds the bucket into the host portion of the URI rather
|
1451
|
+
# than the path, e.g. `https://mybucket.storage.googleapis.com/...`.
|
1452
|
+
# For V4 signing, this also sets the `host` header in the canonicalized
|
1453
|
+
# extension headers to the virtual hosted-style host, unless that header is
|
1454
|
+
# supplied via the `headers` param. The default value of `false` uses the
|
1455
|
+
# form of `https://storage.googleapis.com/mybucket`.
|
1456
|
+
# @param [String] bucket_bound_hostname Use a bucket-bound hostname, which
|
1457
|
+
# replaces the `storage.googleapis.com` host with the name of a `CNAME`
|
1458
|
+
# bucket, e.g. a bucket named `gcs-subdomain.my.domain.tld`, or a Google
|
1459
|
+
# Cloud Load Balancer which routes to a bucket you own, e.g.
|
1460
|
+
# `my-load-balancer-domain.tld`.
|
1443
1461
|
# @param [Symbol, String] version The version of the signed credential
|
1444
1462
|
# to create. Must be one of `:v2` or `:v4`. The default value is
|
1445
1463
|
# `:v2`.
|
@@ -1510,28 +1528,49 @@ module Google
|
|
1510
1528
|
# bucket = storage.bucket "my-todo-app"
|
1511
1529
|
# list_files_url = bucket.signed_url version: :v4
|
1512
1530
|
#
|
1513
|
-
def signed_url path = nil,
|
1514
|
-
|
1515
|
-
|
1516
|
-
|
1531
|
+
def signed_url path = nil,
|
1532
|
+
method: "GET",
|
1533
|
+
expires: nil,
|
1534
|
+
content_type: nil,
|
1535
|
+
content_md5: nil,
|
1536
|
+
headers: nil,
|
1537
|
+
issuer: nil,
|
1538
|
+
client_email: nil,
|
1539
|
+
signing_key: nil,
|
1540
|
+
private_key: nil,
|
1541
|
+
query: nil,
|
1542
|
+
scheme: "HTTPS",
|
1543
|
+
virtual_hosted_style: nil,
|
1544
|
+
bucket_bound_hostname: nil,
|
1545
|
+
version: nil
|
1517
1546
|
ensure_service!
|
1518
1547
|
version ||= :v2
|
1519
1548
|
case version.to_sym
|
1520
1549
|
when :v2
|
1521
1550
|
signer = File::SignerV2.from_bucket self, path
|
1522
|
-
signer.signed_url method: method,
|
1523
|
-
|
1524
|
-
|
1551
|
+
signer.signed_url method: method,
|
1552
|
+
expires: expires,
|
1553
|
+
headers: headers,
|
1554
|
+
content_type: content_type,
|
1555
|
+
content_md5: content_md5,
|
1556
|
+
issuer: issuer,
|
1525
1557
|
client_email: client_email,
|
1526
1558
|
signing_key: signing_key,
|
1527
|
-
private_key: private_key,
|
1559
|
+
private_key: private_key,
|
1560
|
+
query: query
|
1528
1561
|
when :v4
|
1529
1562
|
signer = File::SignerV4.from_bucket self, path
|
1530
|
-
signer.signed_url method: method,
|
1531
|
-
|
1563
|
+
signer.signed_url method: method,
|
1564
|
+
expires: expires,
|
1565
|
+
headers: headers,
|
1566
|
+
issuer: issuer,
|
1532
1567
|
client_email: client_email,
|
1533
1568
|
signing_key: signing_key,
|
1534
|
-
private_key: private_key,
|
1569
|
+
private_key: private_key,
|
1570
|
+
query: query,
|
1571
|
+
scheme: scheme,
|
1572
|
+
virtual_hosted_style: virtual_hosted_style,
|
1573
|
+
bucket_bound_hostname: bucket_bound_hostname
|
1535
1574
|
else
|
1536
1575
|
raise ArgumentError, "version '#{version}' not supported"
|
1537
1576
|
end
|
@@ -1558,12 +1597,13 @@ module Google
|
|
1558
1597
|
#
|
1559
1598
|
# @param [String] path Path to the file in Google Cloud Storage.
|
1560
1599
|
# @param [Hash] policy The security policy that describes what
|
1561
|
-
# can and cannot be uploaded in the form. When provided,
|
1562
|
-
#
|
1563
|
-
#
|
1600
|
+
# can and cannot be uploaded in the form. When provided, the PostObject
|
1601
|
+
# fields will include a signature based on the JSON representation of
|
1602
|
+
# this hash and the same policy in Base64 format.
|
1603
|
+
#
|
1564
1604
|
# If you do not provide a security policy, requests are considered
|
1565
1605
|
# to be anonymous and will only work with buckets that have granted
|
1566
|
-
# WRITE or FULL_CONTROL permission to anonymous users.
|
1606
|
+
# `WRITE` or `FULL_CONTROL` permission to anonymous users.
|
1567
1607
|
# See [Policy Document](https://cloud.google.com/storage/docs/xml-api/post-object#policydocument)
|
1568
1608
|
# for more information.
|
1569
1609
|
# @param [String] issuer Service Account's Client Email.
|
@@ -1633,17 +1673,110 @@ module Google
|
|
1633
1673
|
# post.fields[:signature] #=> "ABC...XYZ="
|
1634
1674
|
# post.fields[:policy] #=> "ABC...XYZ="
|
1635
1675
|
#
|
1636
|
-
def post_object path,
|
1637
|
-
|
1676
|
+
def post_object path,
|
1677
|
+
policy: nil,
|
1678
|
+
issuer: nil,
|
1679
|
+
client_email: nil,
|
1680
|
+
signing_key: nil,
|
1638
1681
|
private_key: nil
|
1639
1682
|
ensure_service!
|
1640
|
-
|
1641
1683
|
signer = File::SignerV2.from_bucket self, path
|
1642
|
-
signer.post_object issuer: issuer,
|
1643
|
-
|
1684
|
+
signer.post_object issuer: issuer,
|
1685
|
+
client_email: client_email,
|
1686
|
+
signing_key: signing_key,
|
1687
|
+
private_key: private_key,
|
1644
1688
|
policy: policy
|
1645
1689
|
end
|
1646
1690
|
|
1691
|
+
##
|
1692
|
+
# Generate a PostObject that includes the fields and url to
|
1693
|
+
# upload objects via html forms.
|
1694
|
+
#
|
1695
|
+
# Generating a PostObject requires service account credentials,
|
1696
|
+
# either by connecting with a service account when calling
|
1697
|
+
# {Google::Cloud.storage}, or by passing in the service account
|
1698
|
+
# `issuer` and `signing_key` values. Although the private key can
|
1699
|
+
# be passed as a string for convenience, creating and storing
|
1700
|
+
# an instance of `OpenSSL::PKey::RSA` is more efficient
|
1701
|
+
# when making multiple calls to `generate_signed_post_policy_v4`.
|
1702
|
+
#
|
1703
|
+
# A {SignedUrlUnavailable} is raised if the service account credentials
|
1704
|
+
# are missing. Service account credentials are acquired by following the
|
1705
|
+
# steps in [Service Account Authentication](
|
1706
|
+
# https://cloud.google.com/storage/docs/authentication#service_accounts).
|
1707
|
+
#
|
1708
|
+
# @see https://cloud.google.com/storage/docs/xml-api/post-object
|
1709
|
+
#
|
1710
|
+
# @param [String] path Path to the file in Google Cloud Storage.
|
1711
|
+
# @param [String] issuer Service Account's Client Email.
|
1712
|
+
# @param [String] client_email Service Account's Client Email.
|
1713
|
+
# @param [OpenSSL::PKey::RSA, String] signing_key Service Account's
|
1714
|
+
# Private Key.
|
1715
|
+
# @param [OpenSSL::PKey::RSA, String] private_key Service Account's
|
1716
|
+
# Private Key.
|
1717
|
+
# @param [Integer] expires The number of seconds until the URL expires.
|
1718
|
+
# The default is 604800 (7 days).
|
1719
|
+
# @param [Hash] fields User-supplied form fields such as `acl`,
|
1720
|
+
# `cache-control`, `success_action_status`, and `success_action_redirect`.
|
1721
|
+
# @param [Array<Hash|Array>] conditions User-supplied policy conditions.
|
1722
|
+
# @param [String] scheme The URL scheme. The default value is `HTTPS`.
|
1723
|
+
# @param [Boolean] virtual_hosted_style Whether to use a virtual hosted-style
|
1724
|
+
# hostname, which adds the bucket into the host portion of the URI rather
|
1725
|
+
# than the path, e.g. `https://mybucket.storage.googleapis.com/...`.
|
1726
|
+
# The default value of `false` uses the
|
1727
|
+
# form of `https://storage.googleapis.com/mybucket`.
|
1728
|
+
# @param [String] bucket_bound_hostname Use a bucket-bound hostname, which
|
1729
|
+
# replaces the `storage.googleapis.com` host with the name of a `CNAME`
|
1730
|
+
# bucket, e.g. a bucket named `gcs-subdomain.my.domain.tld`, or a Google
|
1731
|
+
# Cloud Load Balancer which routes to a bucket you own, e.g.
|
1732
|
+
# `my-load-balancer-domain.tld`.
|
1733
|
+
#
|
1734
|
+
# @return [PostObject] An object containing the URL, fields, and values needed to upload files via html forms.
|
1735
|
+
#
|
1736
|
+
# @example
|
1737
|
+
# require "google/cloud/storage"
|
1738
|
+
#
|
1739
|
+
# storage = Google::Cloud::Storage.new
|
1740
|
+
#
|
1741
|
+
# bucket = storage.bucket "my-todo-app"
|
1742
|
+
#
|
1743
|
+
# conditions = [["starts-with", "$acl","public"]]
|
1744
|
+
# post = bucket.generate_signed_post_policy_v4 "avatars/heidi/400x400.png", expires: 10,
|
1745
|
+
# conditions: conditions
|
1746
|
+
#
|
1747
|
+
# post.url #=> "https://storage.googleapis.com/my-todo-app/"
|
1748
|
+
# post.fields["key"] #=> "my-todo-app/avatars/heidi/400x400.png"
|
1749
|
+
# post.fields["policy"] #=> "ABC...XYZ"
|
1750
|
+
# post.fields["x-goog-algorithm"] #=> "GOOG4-RSA-SHA256"
|
1751
|
+
# post.fields["x-goog-credential"] #=> "cred@pid.iam.gserviceaccount.com/20200123/auto/storage/goog4_request"
|
1752
|
+
# post.fields["x-goog-date"] #=> "20200128T000000Z"
|
1753
|
+
# post.fields["x-goog-signature"] #=> "4893a0e...cd82"
|
1754
|
+
#
|
1755
|
+
def generate_signed_post_policy_v4 path,
|
1756
|
+
issuer: nil,
|
1757
|
+
client_email: nil,
|
1758
|
+
signing_key: nil,
|
1759
|
+
private_key: nil,
|
1760
|
+
expires: nil,
|
1761
|
+
fields: nil,
|
1762
|
+
conditions: nil,
|
1763
|
+
scheme: "https",
|
1764
|
+
virtual_hosted_style: nil,
|
1765
|
+
bucket_bound_hostname: nil
|
1766
|
+
ensure_service!
|
1767
|
+
signer = File::SignerV4.from_bucket self, path
|
1768
|
+
signer.post_object issuer: issuer,
|
1769
|
+
client_email: client_email,
|
1770
|
+
signing_key: signing_key,
|
1771
|
+
private_key: private_key,
|
1772
|
+
expires: expires,
|
1773
|
+
fields: fields,
|
1774
|
+
conditions: conditions,
|
1775
|
+
scheme: scheme,
|
1776
|
+
virtual_hosted_style: virtual_hosted_style,
|
1777
|
+
bucket_bound_hostname: bucket_bound_hostname
|
1778
|
+
end
|
1779
|
+
|
1647
1780
|
##
|
1648
1781
|
# The {Bucket::Acl} instance used to control access to the bucket.
|
1649
1782
|
#
|
@@ -2125,11 +2258,12 @@ module Google
|
|
2125
2258
|
def create_notification topic, custom_attrs: nil, event_types: nil,
|
2126
2259
|
prefix: nil, payload: nil
|
2127
2260
|
ensure_service!
|
2128
|
-
options = { custom_attrs: custom_attrs, event_types: event_types,
|
2129
|
-
prefix: prefix, payload: payload,
|
2130
|
-
user_project: user_project }
|
2131
2261
|
|
2132
|
-
gapi = service.insert_notification name, topic,
|
2262
|
+
gapi = service.insert_notification name, topic, custom_attrs: custom_attrs,
|
2263
|
+
event_types: event_types,
|
2264
|
+
prefix: prefix,
|
2265
|
+
payload: payload,
|
2266
|
+
user_project: user_project
|
2133
2267
|
Notification.from_gapi name, gapi, service, user_project: user_project
|
2134
2268
|
end
|
2135
2269
|
alias new_notification create_notification
|
@@ -2215,7 +2349,7 @@ module Google
|
|
2215
2349
|
patch_args = Hash[attributes.map do |attr|
|
2216
2350
|
[attr, @gapi.send(attr)]
|
2217
2351
|
end]
|
2218
|
-
patch_gapi = API::Bucket.new
|
2352
|
+
patch_gapi = API::Bucket.new(**patch_args)
|
2219
2353
|
@gapi = service.patch_bucket name, patch_gapi,
|
2220
2354
|
user_project: user_project
|
2221
2355
|
@lazy = nil
|
@@ -1479,6 +1479,19 @@ module Google
|
|
1479
1479
|
# using the URL, but only when the file resource is missing the
|
1480
1480
|
# corresponding values. (These values can be permanently set using
|
1481
1481
|
# {#content_disposition=} and {#content_type=}.)
|
1482
|
+
# @param [String] scheme The URL scheme. The default value is `HTTPS`.
|
1483
|
+
# @param [Boolean] virtual_hosted_style Whether to use a virtual hosted-style
|
1484
|
+
# hostname, which adds the bucket into the host portion of the URI rather
|
1485
|
+
# than the path, e.g. `https://mybucket.storage.googleapis.com/...`.
|
1486
|
+
# For V4 signing, this also sets the `host` header in the canonicalized
|
1487
|
+
# extension headers to the virtual hosted-style host, unless that header is
|
1488
|
+
# supplied via the `headers` param. The default value of `false` uses the
|
1489
|
+
# form of `https://storage.googleapis.com/mybucket`.
|
1490
|
+
# @param [String] bucket_bound_hostname Use a bucket-bound hostname, which
|
1491
|
+
# replaces the `storage.googleapis.com` host with the name of a `CNAME`
|
1492
|
+
# bucket, e.g. a bucket named `gcs-subdomain.my.domain.tld`, or a Google
|
1493
|
+
# Cloud Load Balancer which routes to a bucket you own, e.g.
|
1494
|
+
# `my-load-balancer-domain.tld`.
|
1482
1495
|
# @param [Symbol, String] version The version of the signed credential
|
1483
1496
|
# to create. Must be one of `:v2` or `:v4`. The default value is
|
1484
1497
|
# `:v2`.
|
@@ -1503,7 +1516,7 @@ module Google
|
|
1503
1516
|
# file = bucket.file "avatars/heidi/400x400.png"
|
1504
1517
|
# shared_url = file.signed_url expires: 300, # 5 minutes from now
|
1505
1518
|
# version: :v4
|
1506
|
-
|
1519
|
+
#
|
1507
1520
|
# @example Using the `issuer` and `signing_key` options:
|
1508
1521
|
# require "google/cloud/storage"
|
1509
1522
|
#
|
@@ -1543,28 +1556,48 @@ module Google
|
|
1543
1556
|
# # Send the `x-goog-resumable:start` header and the content type
|
1544
1557
|
# # with the resumable upload POST request.
|
1545
1558
|
#
|
1546
|
-
def signed_url method:
|
1547
|
-
|
1548
|
-
|
1549
|
-
|
1559
|
+
def signed_url method: "GET",
|
1560
|
+
expires: nil,
|
1561
|
+
content_type: nil,
|
1562
|
+
content_md5: nil,
|
1563
|
+
headers: nil,
|
1564
|
+
issuer: nil,
|
1565
|
+
client_email: nil,
|
1566
|
+
signing_key: nil,
|
1567
|
+
private_key: nil,
|
1568
|
+
query: nil,
|
1569
|
+
scheme: "HTTPS",
|
1570
|
+
virtual_hosted_style: nil,
|
1571
|
+
bucket_bound_hostname: nil,
|
1572
|
+
version: nil
|
1550
1573
|
ensure_service!
|
1551
1574
|
version ||= :v2
|
1552
1575
|
case version.to_sym
|
1553
1576
|
when :v2
|
1554
1577
|
signer = File::SignerV2.from_file self
|
1555
|
-
signer.signed_url method: method,
|
1556
|
-
|
1557
|
-
|
1578
|
+
signer.signed_url method: method,
|
1579
|
+
expires: expires,
|
1580
|
+
headers: headers,
|
1581
|
+
content_type: content_type,
|
1582
|
+
content_md5: content_md5,
|
1583
|
+
issuer: issuer,
|
1558
1584
|
client_email: client_email,
|
1559
1585
|
signing_key: signing_key,
|
1560
|
-
private_key: private_key,
|
1586
|
+
private_key: private_key,
|
1587
|
+
query: query
|
1561
1588
|
when :v4
|
1562
1589
|
signer = File::SignerV4.from_file self
|
1563
|
-
signer.signed_url method: method,
|
1564
|
-
|
1590
|
+
signer.signed_url method: method,
|
1591
|
+
expires: expires,
|
1592
|
+
headers: headers,
|
1593
|
+
issuer: issuer,
|
1565
1594
|
client_email: client_email,
|
1566
1595
|
signing_key: signing_key,
|
1567
|
-
private_key: private_key,
|
1596
|
+
private_key: private_key,
|
1597
|
+
query: query,
|
1598
|
+
scheme: scheme,
|
1599
|
+
virtual_hosted_style: virtual_hosted_style,
|
1600
|
+
bucket_bound_hostname: bucket_bound_hostname
|
1568
1601
|
else
|
1569
1602
|
raise ArgumentError, "version '#{version}' not supported"
|
1570
1603
|
end
|
@@ -1733,7 +1766,7 @@ module Google
|
|
1733
1766
|
# Sending nil metadata results in an Apiary runtime error:
|
1734
1767
|
# NoMethodError: undefined method `each' for nil:NilClass
|
1735
1768
|
attr_params.reject! { |k, v| k == :metadata && v.nil? }
|
1736
|
-
Google::Apis::StorageV1::Object.new
|
1769
|
+
Google::Apis::StorageV1::Object.new(**attr_params)
|
1737
1770
|
end
|
1738
1771
|
|
1739
1772
|
protected
|
@@ -1784,12 +1817,12 @@ module Google
|
|
1784
1817
|
user_project: user_project }.delete_if { |_k, v| v.nil? }
|
1785
1818
|
|
1786
1819
|
resp = service.rewrite_file \
|
1787
|
-
bucket, name, new_bucket, new_name, updated_gapi, options
|
1820
|
+
bucket, name, new_bucket, new_name, updated_gapi, **options
|
1788
1821
|
until resp.done
|
1789
1822
|
sleep 1
|
1790
1823
|
retry_options = options.merge token: resp.rewrite_token
|
1791
1824
|
resp = service.rewrite_file \
|
1792
|
-
bucket, name, new_bucket, new_name, updated_gapi, retry_options
|
1825
|
+
bucket, name, new_bucket, new_name, updated_gapi, **retry_options
|
1793
1826
|
end
|
1794
1827
|
resp.resource
|
1795
1828
|
end
|
@@ -77,11 +77,13 @@ module Google
|
|
77
77
|
def next
|
78
78
|
return nil unless next?
|
79
79
|
ensure_service!
|
80
|
-
|
81
|
-
|
82
|
-
|
83
|
-
|
84
|
-
|
80
|
+
|
81
|
+
gapi = @service.list_files @bucket, prefix: @prefix,
|
82
|
+
delimiter: @delimiter,
|
83
|
+
token: @token,
|
84
|
+
max: @max,
|
85
|
+
versions: @versions,
|
86
|
+
user_project: @user_project
|
85
87
|
File::List.from_gapi gapi, @service, @bucket, @prefix,
|
86
88
|
@delimiter, @max, @versions,
|
87
89
|
user_project: @user_project
|
@@ -39,37 +39,83 @@ module Google
|
|
39
39
|
new bucket.name, file_name, bucket.service
|
40
40
|
end
|
41
41
|
|
42
|
-
def
|
43
|
-
|
44
|
-
|
45
|
-
|
46
|
-
|
42
|
+
def post_object issuer: nil,
|
43
|
+
client_email: nil,
|
44
|
+
signing_key: nil,
|
45
|
+
private_key: nil,
|
46
|
+
expires: nil,
|
47
|
+
fields: nil,
|
48
|
+
conditions: nil,
|
49
|
+
scheme: "https",
|
50
|
+
virtual_hosted_style: nil,
|
51
|
+
bucket_bound_hostname: nil
|
52
|
+
i = determine_issuer issuer, client_email
|
53
|
+
s = determine_signing_key signing_key, private_key
|
54
|
+
raise SignedUrlUnavailable unless i && s
|
55
|
+
|
56
|
+
now = Time.now.utc
|
57
|
+
base_fields = required_fields i, now
|
58
|
+
post_fields = fields.dup || {}
|
59
|
+
post_fields.merge! base_fields
|
60
|
+
|
61
|
+
p = {}
|
62
|
+
p["conditions"] = policy_conditions base_fields, conditions, fields
|
63
|
+
expires ||= 60*60*24
|
64
|
+
p["expiration"] = (now + expires).strftime "%Y-%m-%dT%H:%M:%SZ"
|
65
|
+
|
66
|
+
|
67
|
+
policy_str = escape_characters p.to_json
|
68
|
+
|
69
|
+
policy = Base64.strict_encode64(policy_str).force_encoding "utf-8"
|
70
|
+
signature = generate_signature s, policy
|
71
|
+
|
72
|
+
post_fields["x-goog-signature"] = signature
|
73
|
+
post_fields["policy"] = policy
|
74
|
+
url = post_object_ext_url scheme, virtual_hosted_style, bucket_bound_hostname
|
75
|
+
hostname = "#{url}#{bucket_path path_style?(virtual_hosted_style, bucket_bound_hostname)}"
|
76
|
+
Google::Cloud::Storage::PostObject.new hostname, post_fields
|
77
|
+
end
|
78
|
+
|
79
|
+
def signed_url method: "GET",
|
80
|
+
expires: nil,
|
81
|
+
headers: nil,
|
82
|
+
issuer: nil,
|
83
|
+
client_email: nil,
|
84
|
+
signing_key: nil,
|
85
|
+
private_key: nil,
|
86
|
+
query: nil,
|
87
|
+
scheme: "https",
|
88
|
+
virtual_hosted_style: nil,
|
89
|
+
bucket_bound_hostname: nil
|
90
|
+
raise ArgumentError, "method is required" unless method
|
91
|
+
issuer, signer = issuer_and_signer issuer, client_email, signing_key, private_key
|
47
92
|
datetime_now = Time.now.utc
|
48
93
|
goog_date = datetime_now.strftime "%Y%m%dT%H%M%SZ"
|
49
94
|
datestamp = datetime_now.strftime "%Y%m%d"
|
50
95
|
# goog4_request is not checked.
|
51
96
|
scope = "#{datestamp}/auto/storage/goog4_request"
|
52
97
|
|
53
|
-
canonical_headers_str, signed_headers_str = \
|
54
|
-
|
98
|
+
canonical_headers_str, signed_headers_str = canonical_and_signed_headers \
|
99
|
+
headers, virtual_hosted_style, bucket_bound_hostname
|
55
100
|
|
56
101
|
algorithm = "GOOG4-RSA-SHA256"
|
57
102
|
expires = determine_expires expires
|
58
|
-
credential =
|
59
|
-
canonical_query_str = canonical_query query, algorithm,
|
60
|
-
credential, goog_date,
|
61
|
-
expires, signed_headers_str
|
103
|
+
credential = issuer + "/" + scope
|
104
|
+
canonical_query_str = canonical_query query, algorithm, credential, goog_date, expires, signed_headers_str
|
62
105
|
|
63
106
|
# From AWS: You don't include a payload hash in the Canonical
|
64
107
|
# Request, because when you create a presigned URL, you don't know
|
65
108
|
# the payload content because the URL is used to upload an arbitrary
|
66
109
|
# payload. Instead, you use a constant string UNSIGNED-PAYLOAD.
|
110
|
+
payload = headers&.key?("X-Goog-Content-SHA256") ? headers["X-Goog-Content-SHA256"] : "UNSIGNED-PAYLOAD"
|
111
|
+
|
67
112
|
canonical_request = [method,
|
68
|
-
|
113
|
+
file_path(!(virtual_hosted_style || bucket_bound_hostname)),
|
69
114
|
canonical_query_str,
|
70
115
|
canonical_headers_str,
|
71
116
|
signed_headers_str,
|
72
|
-
|
117
|
+
payload].join("\n")
|
118
|
+
|
73
119
|
# Construct string to sign
|
74
120
|
req_sha = Digest::SHA256.hexdigest canonical_request
|
75
121
|
string_to_sign = [algorithm, goog_date, scope, req_sha].join "\n"
|
@@ -78,33 +124,85 @@ module Google
|
|
78
124
|
signature = signer.call string_to_sign
|
79
125
|
|
80
126
|
# Construct signed URL
|
81
|
-
|
127
|
+
hostname = signed_url_hostname scheme, virtual_hosted_style, bucket_bound_hostname
|
128
|
+
"#{hostname}?#{canonical_query_str}&X-Goog-Signature=#{signature}"
|
129
|
+
end
|
130
|
+
|
131
|
+
# methods below are public visibility only for unit testing
|
132
|
+
def escape_characters str
|
133
|
+
str.split("").map do |s|
|
134
|
+
if !s.ascii_only?
|
135
|
+
escape_special_unicode s
|
136
|
+
else
|
137
|
+
case s
|
138
|
+
when "\\"
|
139
|
+
'\\'
|
140
|
+
when "\b"
|
141
|
+
'\b'
|
142
|
+
when "\f"
|
143
|
+
'\f'
|
144
|
+
when "\n"
|
145
|
+
'\n'
|
146
|
+
when "\r"
|
147
|
+
'\r'
|
148
|
+
when "\t"
|
149
|
+
'\t'
|
150
|
+
when "\v"
|
151
|
+
'\v'
|
152
|
+
else
|
153
|
+
s
|
154
|
+
end
|
155
|
+
end
|
156
|
+
end.join
|
157
|
+
end
|
158
|
+
|
159
|
+
def escape_special_unicode str
|
160
|
+
str.unpack("U*").map { |i| '\u' + i.to_s(16).rjust(4, "0") }.join
|
82
161
|
end
|
83
162
|
|
84
163
|
protected
|
85
164
|
|
165
|
+
def required_fields issuer, time
|
166
|
+
{
|
167
|
+
"key" => @file_name,
|
168
|
+
"x-goog-date" => time.strftime("%Y%m%dT%H%M%SZ"),
|
169
|
+
"x-goog-credential" => "#{issuer}/#{time.strftime '%Y%m%d'}/auto/storage/goog4_request",
|
170
|
+
"x-goog-algorithm" => "GOOG4-RSA-SHA256"
|
171
|
+
}.freeze
|
172
|
+
end
|
173
|
+
|
174
|
+
def policy_conditions base_fields, user_conditions, user_fields
|
175
|
+
# Convert each pair in base_fields hash to a single-entry hash in an array.
|
176
|
+
conditions = base_fields.to_a.map { |f| Hash[*f] }
|
177
|
+
# Add user-provided conditions to the head of the conditions array.
|
178
|
+
conditions.unshift user_conditions if user_conditions && !user_conditions.empty?
|
179
|
+
if user_fields
|
180
|
+
# Convert each pair in fields hash to a single-entry hash and add it to the head of the conditions array.
|
181
|
+
user_fields.to_a.reverse.each { |f| conditions.unshift Hash[*f] }
|
182
|
+
end
|
183
|
+
conditions.freeze
|
184
|
+
end
|
185
|
+
|
186
|
+
def signed_url_hostname scheme, virtual_hosted_style, bucket_bound_hostname
|
187
|
+
url = ext_url scheme, virtual_hosted_style, bucket_bound_hostname
|
188
|
+
"#{url}#{file_path path_style?(virtual_hosted_style, bucket_bound_hostname)}"
|
189
|
+
end
|
190
|
+
|
86
191
|
def determine_issuer issuer, client_email
|
87
192
|
# Parse the Service Account and get client id and private key
|
88
193
|
issuer = issuer || client_email || @service.credentials.issuer
|
89
|
-
unless issuer
|
90
|
-
raise SignedUrlUnavailable, "issuer (client_email) missing"
|
91
|
-
end
|
194
|
+
raise SignedUrlUnavailable, "issuer (client_email) missing" unless issuer
|
92
195
|
issuer
|
93
196
|
end
|
94
197
|
|
95
198
|
def determine_signing_key signing_key, private_key
|
96
|
-
signing_key = signing_key || private_key ||
|
97
|
-
|
98
|
-
unless signing_key
|
99
|
-
raise SignedUrlUnavailable, "signing_key (private_key) missing"
|
100
|
-
end
|
199
|
+
signing_key = signing_key || private_key || @service.credentials.signing_key
|
200
|
+
raise SignedUrlUnavailable, "signing_key (private_key) missing" unless signing_key
|
101
201
|
signing_key
|
102
202
|
end
|
103
203
|
|
104
204
|
def service_account_signer signer
|
105
|
-
unless signer.respond_to? :sign
|
106
|
-
signer = OpenSSL::PKey::RSA.new signer
|
107
|
-
end
|
205
|
+
signer = OpenSSL::PKey::RSA.new signer unless signer.respond_to? :sign
|
108
206
|
# Sign string to sign
|
109
207
|
lambda do |string_to_sign|
|
110
208
|
sig = signer.sign OpenSSL::Digest::SHA256.new, string_to_sign
|
@@ -119,25 +217,22 @@ module Google
|
|
119
217
|
[issuer, signer]
|
120
218
|
end
|
121
219
|
|
122
|
-
def canonical_and_signed_headers headers
|
123
|
-
|
220
|
+
def canonical_and_signed_headers headers, virtual_hosted_style, bucket_bound_hostname
|
221
|
+
if virtual_hosted_style && bucket_bound_hostname
|
222
|
+
raise "virtual_hosted_style: #{virtual_hosted_style} and bucket_bound_hostname: " \
|
223
|
+
"#{bucket_bound_hostname} params cannot both be passed together"
|
224
|
+
end
|
225
|
+
|
124
226
|
canonical_headers = headers || {}
|
125
227
|
headers_arr = canonical_headers.map do |k, v|
|
126
|
-
[k.downcase, v.strip.gsub(/[^\S\t]+/, " ").gsub(/\t+/, "
|
228
|
+
[k.downcase, v.strip.gsub(/[^\S\t]+/, " ").gsub(/\t+/, " ")]
|
127
229
|
end
|
128
230
|
canonical_headers = Hash[headers_arr]
|
129
|
-
canonical_headers["host"] =
|
130
|
-
|
131
|
-
canonical_headers = canonical_headers.sort_by
|
132
|
-
|
133
|
-
|
134
|
-
canonical_headers_str = ""
|
135
|
-
canonical_headers.each do |k, v|
|
136
|
-
canonical_headers_str += "#{k}:#{v}\n"
|
137
|
-
end
|
138
|
-
signed_headers_str = ""
|
139
|
-
canonical_headers.each_key { |k| signed_headers_str += "#{k};" }
|
140
|
-
signed_headers_str = signed_headers_str.chomp ";"
|
231
|
+
canonical_headers["host"] = host_name virtual_hosted_style, bucket_bound_hostname
|
232
|
+
|
233
|
+
canonical_headers = canonical_headers.sort_by(&:first).to_h
|
234
|
+
canonical_headers_str = canonical_headers.map { |k, v| "#{k}:#{v}\n" }.join
|
235
|
+
signed_headers_str = canonical_headers.keys.join ";"
|
141
236
|
[canonical_headers_str, signed_headers_str]
|
142
237
|
end
|
143
238
|
|
@@ -149,32 +244,103 @@ module Google
|
|
149
244
|
expires
|
150
245
|
end
|
151
246
|
|
152
|
-
def canonical_query query, algorithm, credential, goog_date, expires,
|
153
|
-
signed_headers_str
|
247
|
+
def canonical_query query, algorithm, credential, goog_date, expires, signed_headers_str
|
154
248
|
query ||= {}
|
155
249
|
query["X-Goog-Algorithm"] = algorithm
|
156
250
|
query["X-Goog-Credential"] = credential
|
157
251
|
query["X-Goog-Date"] = goog_date
|
158
252
|
query["X-Goog-Expires"] = expires
|
159
|
-
query["X-Goog-SignedHeaders"] =
|
160
|
-
query = query.
|
161
|
-
|
162
|
-
|
163
|
-
|
253
|
+
query["X-Goog-SignedHeaders"] = signed_headers_str
|
254
|
+
query = query.map { |k, v| [escape_query_param(k), escape_query_param(v)] }.sort_by(&:first).to_h
|
255
|
+
query.map { |k, v| "#{k}=#{v}" }.join "&"
|
256
|
+
end
|
257
|
+
|
258
|
+
##
|
259
|
+
# Only the characters in the regex set [A-Za-z0-9.~_-] must be left un-escaped; all others must be
|
260
|
+
# percent-encoded using %XX UTF-8 style.
|
261
|
+
def escape_query_param str
|
262
|
+
CGI.escape(str.to_s).gsub("%7E", "~")
|
263
|
+
end
|
264
|
+
|
265
|
+
def host_name virtual_hosted_style, bucket_bound_hostname
|
266
|
+
return bucket_bound_hostname if bucket_bound_hostname
|
267
|
+
virtual_hosted_style ? "#{@bucket_name}.storage.googleapis.com" : "storage.googleapis.com"
|
164
268
|
end
|
165
269
|
|
166
270
|
##
|
167
271
|
# The URI-encoded (percent encoded) external path to the file.
|
168
|
-
def
|
169
|
-
path =
|
170
|
-
path
|
171
|
-
|
272
|
+
def file_path path_style
|
273
|
+
path = []
|
274
|
+
path << "/#{@bucket_name}" if path_style
|
275
|
+
path << "/#{String(@file_name)}" if @file_name && !@file_name.empty?
|
276
|
+
CGI.escape(path.join).gsub "%2F", "/"
|
277
|
+
end
|
278
|
+
|
279
|
+
##
|
280
|
+
# The external path to the bucket, with trailing slash.
|
281
|
+
def bucket_path path_style
|
282
|
+
return "/#{@bucket_name}/" if path_style
|
172
283
|
end
|
173
284
|
|
174
285
|
##
|
175
286
|
# The external url to the file.
|
176
|
-
def ext_url
|
177
|
-
|
287
|
+
def ext_url scheme, virtual_hosted_style, bucket_bound_hostname
|
288
|
+
url = GOOGLEAPIS_URL.dup
|
289
|
+
if virtual_hosted_style
|
290
|
+
parts = url.split "//"
|
291
|
+
parts[1] = "#{@bucket_name}.#{parts[1]}"
|
292
|
+
parts.join "//"
|
293
|
+
elsif bucket_bound_hostname
|
294
|
+
raise ArgumentError, "scheme is required" unless scheme
|
295
|
+
URI "#{scheme.to_s.downcase}://#{bucket_bound_hostname}"
|
296
|
+
else
|
297
|
+
url
|
298
|
+
end
|
299
|
+
end
|
300
|
+
|
301
|
+
def path_style? virtual_hosted_style, bucket_bound_hostname
|
302
|
+
!(virtual_hosted_style || bucket_bound_hostname)
|
303
|
+
end
|
304
|
+
|
305
|
+
##
|
306
|
+
# The external path to the file, URI-encoded.
|
307
|
+
# Will not URI encode the special `${filename}` variable.
|
308
|
+
# "You can also use the ${filename} variable..."
|
309
|
+
# https://cloud.google.com/storage/docs/xml-api/post-object
|
310
|
+
#
|
311
|
+
def post_object_ext_path
|
312
|
+
path = "/#{@bucket_name}/#{@file_name}"
|
313
|
+
escaped = Addressable::URI.escape path
|
314
|
+
special_var = "${filename}"
|
315
|
+
# Restore the unencoded `${filename}` variable, if present.
|
316
|
+
if path.include? special_var
|
317
|
+
return escaped.gsub "$%7Bfilename%7D", special_var
|
318
|
+
end
|
319
|
+
escaped
|
320
|
+
end
|
321
|
+
|
322
|
+
##
|
323
|
+
# The external url to the file.
|
324
|
+
def post_object_ext_url scheme, virtual_hosted_style, bucket_bound_hostname
|
325
|
+
url = GOOGLEAPIS_URL.dup
|
326
|
+
if virtual_hosted_style
|
327
|
+
parts = url.split "//"
|
328
|
+
parts[1] = "#{@bucket_name}.#{parts[1]}/"
|
329
|
+
parts.join "//"
|
330
|
+
elsif bucket_bound_hostname
|
331
|
+
raise ArgumentError, "scheme is required" unless scheme
|
332
|
+
URI "#{scheme.to_s.downcase}://#{bucket_bound_hostname}/"
|
333
|
+
else
|
334
|
+
url
|
335
|
+
end
|
336
|
+
end
|
337
|
+
|
338
|
+
def generate_signature signing_key, data
|
339
|
+
unless signing_key.respond_to? :sign
|
340
|
+
signing_key = OpenSSL::PKey::RSA.new signing_key
|
341
|
+
end
|
342
|
+
signature = signing_key.sign OpenSSL::Digest::SHA256.new, data
|
343
|
+
signature.unpack("H*").first.force_encoding "utf-8"
|
178
344
|
end
|
179
345
|
end
|
180
346
|
end
|
@@ -230,11 +230,12 @@ module Google
|
|
230
230
|
##
|
231
231
|
# @private
|
232
232
|
def to_gapi
|
233
|
-
|
233
|
+
params = {
|
234
234
|
role: @role,
|
235
235
|
members: @members,
|
236
236
|
condition: @condition&.to_gapi
|
237
|
-
}.delete_if { |_, v| v.nil? }
|
237
|
+
}.delete_if { |_, v| v.nil? }
|
238
|
+
Google::Apis::StorageV1::Policy::Binding.new(**params)
|
238
239
|
end
|
239
240
|
end
|
240
241
|
end
|
@@ -27,7 +27,7 @@ module Google
|
|
27
27
|
# form. Each key/value pair should be set as an input tag's name and
|
28
28
|
# value.
|
29
29
|
#
|
30
|
-
# @example
|
30
|
+
# @example Using Bucket#post_object (V2):
|
31
31
|
# require "google/cloud/storage"
|
32
32
|
#
|
33
33
|
# storage = Google::Cloud::Storage.new
|
@@ -41,6 +41,23 @@ module Google
|
|
41
41
|
# post.fields[:signature] #=> "ABC...XYZ="
|
42
42
|
# post.fields[:policy] #=> "ABC...XYZ="
|
43
43
|
#
|
44
|
+
# @example Using Bucket#generate_signed_post_policy_v4 (V4):
|
45
|
+
# require "google/cloud/storage"
|
46
|
+
#
|
47
|
+
# storage = Google::Cloud::Storage.new
|
48
|
+
#
|
49
|
+
# bucket = storage.bucket "my-todo-app"
|
50
|
+
# conditions = [["starts-with","$acl","public"]]
|
51
|
+
# post = bucket.generate_signed_post_policy_v4 "avatars/heidi/400x400.png", expires: 10, conditions: conditions
|
52
|
+
#
|
53
|
+
# post.url #=> "https://storage.googleapis.com/my-todo-app/"
|
54
|
+
# post.fields["key"] #=> "my-todo-app/avatars/heidi/400x400.png"
|
55
|
+
# post.fields["policy"] #=> "ABC...XYZ"
|
56
|
+
# post.fields["x-goog-algorithm"] #=> "GOOG4-RSA-SHA256"
|
57
|
+
# post.fields["x-goog-credential"] #=> "cred@pid.iam.gserviceaccount.com/20200123/auto/storage/goog4_request"
|
58
|
+
# post.fields["x-goog-date"] #=> "20200128T000000Z"
|
59
|
+
# post.fields["x-goog-signature"] #=> "4893a0e...cd82"
|
60
|
+
#
|
44
61
|
class PostObject
|
45
62
|
attr_reader :url, :fields
|
46
63
|
|
@@ -357,10 +357,11 @@ module Google
|
|
357
357
|
logging_bucket: nil, logging_prefix: nil,
|
358
358
|
website_main: nil, website_404: nil, versioning: nil,
|
359
359
|
requester_pays: nil, user_project: nil
|
360
|
-
|
360
|
+
params = {
|
361
361
|
name: bucket_name,
|
362
362
|
location: location
|
363
|
-
}.delete_if { |_, v| v.nil? }
|
363
|
+
}.delete_if { |_, v| v.nil? }
|
364
|
+
new_bucket = Google::Apis::StorageV1::Bucket.new(**params)
|
364
365
|
storage_class = storage_class_for storage_class
|
365
366
|
updater = Bucket::Updater.new(new_bucket).tap do |b|
|
366
367
|
b.logging_bucket = logging_bucket unless logging_bucket.nil?
|
@@ -522,6 +523,19 @@ module Google
|
|
522
523
|
# using the URL, but only when the file resource is missing the
|
523
524
|
# corresponding values. (These values can be permanently set using
|
524
525
|
# {File#content_disposition=} and {File#content_type=}.)
|
526
|
+
# @param [String] scheme The URL scheme. The default value is `HTTPS`.
|
527
|
+
# @param [Boolean] virtual_hosted_style Whether to use a virtual hosted-style
|
528
|
+
# hostname, which adds the bucket into the host portion of the URI rather
|
529
|
+
# than the path, e.g. `https://mybucket.storage.googleapis.com/...`.
|
530
|
+
# For V4 signing, this also sets the `host` header in the canonicalized
|
531
|
+
# extension headers to the virtual hosted-style host, unless that header is
|
532
|
+
# supplied via the `headers` param. The default value of `false` uses the
|
533
|
+
# form of `https://storage.googleapis.com/mybucket`.
|
534
|
+
# @param [String] bucket_bound_hostname Use a bucket-bound hostname, which
|
535
|
+
# replaces the `storage.googleapis.com` host with the name of a `CNAME`
|
536
|
+
# bucket, e.g. a bucket named `gcs-subdomain.my.domain.tld`, or a Google
|
537
|
+
# Cloud Load Balancer which routes to a bucket you own, e.g.
|
538
|
+
# `my-load-balancer-domain.tld`.
|
525
539
|
# @param [Symbol, String] version The version of the signed credential
|
526
540
|
# to create. Must be one of `:v2` or `:v4`. The default value is
|
527
541
|
# `:v2`.
|
@@ -591,28 +605,50 @@ module Google
|
|
591
605
|
# # Send the `x-goog-resumable:start` header and the content type
|
592
606
|
# # with the resumable upload POST request.
|
593
607
|
#
|
594
|
-
def signed_url bucket,
|
595
|
-
|
596
|
-
|
597
|
-
|
608
|
+
def signed_url bucket,
|
609
|
+
path,
|
610
|
+
method: "GET",
|
611
|
+
expires: nil,
|
612
|
+
content_type: nil,
|
613
|
+
content_md5: nil,
|
614
|
+
headers: nil,
|
615
|
+
issuer: nil,
|
616
|
+
client_email: nil,
|
617
|
+
signing_key: nil,
|
618
|
+
private_key: nil,
|
619
|
+
query: nil,
|
620
|
+
scheme: "HTTPS",
|
621
|
+
virtual_hosted_style: nil,
|
622
|
+
bucket_bound_hostname: nil,
|
623
|
+
version: nil
|
598
624
|
version ||= :v2
|
599
625
|
case version.to_sym
|
600
626
|
when :v2
|
601
627
|
signer = File::SignerV2.new bucket, path, service
|
602
628
|
|
603
|
-
signer.signed_url method: method,
|
604
|
-
|
605
|
-
|
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,
|
606
635
|
client_email: client_email,
|
607
636
|
signing_key: signing_key,
|
608
|
-
private_key: private_key,
|
637
|
+
private_key: private_key,
|
638
|
+
query: query
|
609
639
|
when :v4
|
610
640
|
signer = File::SignerV4.new bucket, path, service
|
611
|
-
signer.signed_url method: method,
|
612
|
-
|
641
|
+
signer.signed_url method: method,
|
642
|
+
expires: expires,
|
643
|
+
headers: headers,
|
644
|
+
issuer: issuer,
|
613
645
|
client_email: client_email,
|
614
646
|
signing_key: signing_key,
|
615
|
-
private_key: private_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
|
616
652
|
else
|
617
653
|
raise ArgumentError, "version '#{version}' not supported"
|
618
654
|
end
|
@@ -152,9 +152,8 @@ module Google
|
|
152
152
|
##
|
153
153
|
# Creates a new bucket ACL.
|
154
154
|
def insert_bucket_acl bucket_name, entity, role, user_project: nil
|
155
|
-
|
156
|
-
|
157
|
-
)
|
155
|
+
params = { entity: entity, role: role }.delete_if { |_k, v| v.nil? }
|
156
|
+
new_acl = Google::Apis::StorageV1::BucketAccessControl.new(**params)
|
158
157
|
execute do
|
159
158
|
service.insert_bucket_access_control \
|
160
159
|
bucket_name, new_acl, user_project: user_project(user_project)
|
@@ -182,9 +181,8 @@ module Google
|
|
182
181
|
##
|
183
182
|
# Creates a new default ACL.
|
184
183
|
def insert_default_acl bucket_name, entity, role, user_project: nil
|
185
|
-
|
186
|
-
|
187
|
-
)
|
184
|
+
param = { entity: entity, role: role }.delete_if { |_k, v| v.nil? }
|
185
|
+
new_acl = Google::Apis::StorageV1::ObjectAccessControl.new(**param)
|
188
186
|
execute do
|
189
187
|
service.insert_default_object_access_control \
|
190
188
|
bucket_name, new_acl, user_project: user_project(user_project)
|
@@ -243,13 +241,13 @@ module Google
|
|
243
241
|
def insert_notification bucket_name, topic_name, custom_attrs: nil,
|
244
242
|
event_types: nil, prefix: nil, payload: nil,
|
245
243
|
user_project: nil
|
246
|
-
|
244
|
+
params =
|
247
245
|
{ custom_attributes: custom_attrs,
|
248
246
|
event_types: event_types(event_types),
|
249
247
|
object_name_prefix: prefix,
|
250
248
|
payload_format: payload_format(payload),
|
251
249
|
topic: topic_path(topic_name) }.delete_if { |_k, v| v.nil? }
|
252
|
-
)
|
250
|
+
new_notification = Google::Apis::StorageV1::Notification.new(**params)
|
253
251
|
|
254
252
|
execute do
|
255
253
|
service.insert_notification \
|
@@ -298,14 +296,14 @@ module Google
|
|
298
296
|
storage_class: nil, key: nil, kms_key: nil,
|
299
297
|
temporary_hold: nil, event_based_hold: nil,
|
300
298
|
user_project: nil
|
301
|
-
|
299
|
+
params =
|
302
300
|
{ cache_control: cache_control, content_type: content_type,
|
303
301
|
content_disposition: content_disposition, md5_hash: md5,
|
304
302
|
content_encoding: content_encoding, crc32c: crc32c,
|
305
303
|
content_language: content_language, metadata: metadata,
|
306
304
|
storage_class: storage_class, temporary_hold: temporary_hold,
|
307
305
|
event_based_hold: event_based_hold }.delete_if { |_k, v| v.nil? }
|
308
|
-
)
|
306
|
+
file_obj = Google::Apis::StorageV1::Object.new(**params)
|
309
307
|
content_type ||= mime_type_for(path || Pathname(source).to_path)
|
310
308
|
|
311
309
|
execute do
|
@@ -432,9 +430,8 @@ module Google
|
|
432
430
|
# Creates a new file ACL.
|
433
431
|
def insert_file_acl bucket_name, file_name, entity, role,
|
434
432
|
generation: nil, user_project: nil
|
435
|
-
|
436
|
-
|
437
|
-
)
|
433
|
+
params = { entity: entity, role: role }.delete_if { |_k, v| v.nil? }
|
434
|
+
new_acl = Google::Apis::StorageV1::ObjectAccessControl.new(**params)
|
438
435
|
execute do
|
439
436
|
service.insert_object_access_control \
|
440
437
|
bucket_name, file_name, new_acl,
|
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.
|
4
|
+
version: 1.26.0
|
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-
|
12
|
+
date: 2020-04-06 00:00:00.000000000 Z
|
13
13
|
dependencies:
|
14
14
|
- !ruby/object:Gem::Dependency
|
15
15
|
name: google-cloud-core
|