google-cloud-storage 1.25.1 → 1.26.0
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.
- 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
|