Class: GcsSigner
- Inherits:
-
Object
- Object
- GcsSigner
- Defined in:
- lib/gcs_signer.rb,
lib/gcs_signer/version.rb
Overview
Creates signed_url for a file on Google Cloud Storage.
signer = GcsSigner.new(path: "/Users/leo/private/service_account.json")
signer.sign "your-bucket", "object/name"
# => "https://storage.googleapis.com/your-bucket/object/name?..."
Defined Under Namespace
Classes: AuthError
Constant Summary collapse
- DEFAULT_GCS_URL =
Addressable::URI.new( scheme: "https", host: "storage.googleapis.com" ).freeze
- VERSION =
"0.4.1"
Instance Method Summary collapse
-
#initialize(path: nil, keyfile_json: nil, gcs_url: DEFAULT_GCS_URL) ⇒ GcsSigner
constructor
gcs-signer requires credential that can access to GCS.
-
#inspect ⇒ String
Prevents confidential information (like private key) from exposing when used with interactive shell such as pry and irb.
-
#sign_url(bucket, key, version: :v2, **options) ⇒ String
Generates signed url.
- #sign_url_v2(bucket, key, method: "GET", valid_for: 300, **options) ⇒ Object
- #sign_url_v4(bucket, key, method: "GET", headers: {}, **options) ⇒ Object
Constructor Details
#initialize(path: nil, keyfile_json: nil, gcs_url: DEFAULT_GCS_URL) ⇒ GcsSigner
gcs-signer requires credential that can access to GCS.
- path
-
the path of the service_account json file.
- keyfile_string
-
…or the content of the service_account json file.
- gcs_url
-
Custom GCS url when signing a url.
or if you also use google-cloud gem. you can authenticate using environment variable that uses.
25 26 27 28 29 30 31 32 |
# File 'lib/gcs_signer.rb', line 25 def initialize(path: nil, keyfile_json: nil, gcs_url: DEFAULT_GCS_URL) keyfile_json ||= path.nil? ? look_for_environment_variables : File.read(path) fail AuthError, "No credentials given." if keyfile_json.nil? @credentials = JSON.parse(keyfile_json) @key = OpenSSL::PKey::RSA.new(@credentials["private_key"]) @gcs_url = Addressable::URI.parse(gcs_url) end |
Instance Method Details
#inspect ⇒ String
Prevents confidential information (like private key) from exposing when used with interactive shell such as pry and irb.
116 117 118 119 120 |
# File 'lib/gcs_signer.rb', line 116 def inspect "#<GcsSigner " \ "project_id: #{@credentials['project_id']} " \ "client_email: #{@credentials['client_email']}>" end |
#sign_url(bucket, key, version: :v2, **options) ⇒ String
Generates signed url.
- bucket
-
the name of the Cloud Storage bucket that contains the object.
- key
-
the name of the object for signed url.
Variable options are available:
- version
-
signature version; :v2 or :v4
- expires
-
Time(stamp in UTC) when the signed url expires.
- valid_for
-
…or how much seconds is the signed url available.
- response_content_disposition
-
Content-Disposition of the signed URL.
- response_content_type
-
Content-Type of the signed URL.
If you set neither expires nor valid_for, it will set to 300 seconds by default.
# default is 5 minutes
signer.sign_url("bucket-name", "path/to/file")
# You can give Time object.
signer.sign_url("bucket-name", "path/to/file",
expires: Time.new(2016, 12, 26, 14, 31, 48, "+09:00"))
# You can give how much seconds is the signed url valid.
signer.sign_url("bucket", "path/to/file", valid_for: 30 * 60)
# If you use ActiveSupport, you can also do some magic.
signer.sign_url("bucket", "path/to/file", valid_for: 40.minutes)
61 62 63 64 65 66 67 68 69 70 |
# File 'lib/gcs_signer.rb', line 61 def sign_url(bucket, key, version: :v2, **) case version when :v2 sign_url_v2(bucket, key, **) when :v4 sign_url_v4(bucket, key, **) else fail ArgumentError, "Version not supported: #{version.inspect}" end end |
#sign_url_v2(bucket, key, method: "GET", valid_for: 300, **options) ⇒ Object
72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 |
# File 'lib/gcs_signer.rb', line 72 def sign_url_v2(bucket, key, method: "GET", valid_for: 300, **) url = @gcs_url + "./#{request_path(bucket, key)}" expires_at = [:expires] || Time.now.utc.to_i + valid_for.to_i sign_payload = [method, "", "", expires_at.to_i, url.path].join("\n") url.query_values = ([:params] || {}).merge( "GoogleAccessId" => @credentials["client_email"], "Expires" => expires_at.to_i, "Signature" => sign_v2(sign_payload), "response-content-disposition" => [:response_content_disposition], "response-content-type" => [:response_content_type] ).compact url.to_s end |
#sign_url_v4(bucket, key, method: "GET", headers: {}, **options) ⇒ Object
88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 |
# File 'lib/gcs_signer.rb', line 88 def sign_url_v4(bucket, key, method: "GET", headers: {}, **) url = @gcs_url + "./#{request_path(bucket, key)}" time = Time.now.utc request_headers = headers.merge(host: @gcs_url.host).transform_keys(&:downcase) signed_headers = request_headers.keys.sort.join(";") scopes = [time.strftime("%Y%m%d"), "auto", "storage", "goog4_request"].join("/") url.query_values = build_query_params(time, scopes, signed_headers, **) canonical_request = [ method, url.path.to_s, url.query, *request_headers.sort.map { |header| header.join(":") }, "", signed_headers, "UNSIGNED-PAYLOAD" ].join("\n") sign_payload = [ "GOOG4-RSA-SHA256", time.strftime("%Y%m%dT%H%M%SZ"), scopes, Digest::SHA256.hexdigest(canonical_request) ].join("\n") url.query += "&X-Goog-Signature=#{sign_v4(sign_payload)}" url.to_s end |